Swift_技巧(3)_Aspects切面編程應用

一丶介紹

Aspect Oriented Programming(AOP),面向切面編程

AOP主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。

[1] 比如我們最常見的就是日志記錄了,舉個例子,我們現在提供一個服務查詢學生信息的,但是我們希望記錄有誰進行了這個查詢。如果按照傳統的OOP的實現的話,那我們實現了一個查詢學生信息的服務接口(StudentInfoService)和其實現類(StudentInfoServiceImpl.java),同時為了要進行記錄的話,那我們在實現類(StudentInfoServiceImpl.java)中要添加其實現記錄的過程。這樣的話,假如我們要實現的服務有多個呢?那就要在每個實現的類都添加這些記錄過程。這樣做的話就會有點繁瑣,而且每個實現類都與記錄服務日志的行為緊耦合,違反了面向對象的規則。那么怎樣才能把記錄服務的行為與業務處理過程中分離出來呢?看起來好像就是查詢學生的服務自己在進行,但卻是背后日志記錄對這些行為進行記錄,并且查詢學生的服務不知道存在這些記錄過程,這就是我們要討論AOP的目的所在。AOP的編程,好像就是把我們在某個方面的功能提出來與一批對象進行隔離,這樣與一批對象之間降低了耦合性,可以就某個功能進行編程。
---摘自百度百科

我們要用AOP來做什么呢?
1.搭建Control的時候,一般會寫個BaseViewController,然后把相同功能的代碼放在相同的函數內比如以下:

- (void)viewDidLoad
{
    [super viewDidLoad];
    //創建視圖代碼
    [self createUI];
   //初始化數據
    [self initdata];
   //網絡請求
    [self askNetwork];
}

規范代碼,可以減少不同開發者之間溝通成本,以及提高問題的定位速度,減少解決時間;
鑒于BaseViewController太臃腫,有了aop編程,就有了新的解決方案;

二丶Aspects的介紹

OC 有一個成熟的aspect方案->Aspects
地址:https://github.com/steipete/Aspects
源碼解析及應用:http://wereadteam.github.io/2016/06/30/Aspects/

主要還是用到oc神奇的runtime機制,動態的改變了 selector 和 IMP 的對應關系;(此圖并非原創)

Paste_Image.png

主要用到2個方法:

+ (id<AspectToken>)aspect_hookSelector:(SEL)selector
                           withOptions:(AspectOptions)options
                            usingBlock:(id)block
                                 error:(NSError **)error;

/// Adds a block of code before/instead/after the current `selector` for a specific instance.
- (id<AspectToken>)aspect_hookSelector:(SEL)selector
                           withOptions:(AspectOptions)options
                            usingBlock:(id)block
                                 error:(NSError **)error;

block 執行的時機

typedef NS_OPTIONS(NSUInteger, AspectOptions) {
    AspectPositionAfter   = 0,            /// Called after the original implementation (default)
    AspectPositionInstead = 1,            /// Will replace the original implementation.
    AspectPositionBefore  = 2,            /// Called before the original implementation.
    AspectOptionAutomaticRemoval = 1 << 3 /// Will remove the hook after the first execution.
};

三丶Aspect OC應用

@implementation UIViewController (Base)
+ (void)load
{
    NSError *error = nil;
    [self aspect_hookSelector:@selector(viewDidLoad) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo){
        
        UIViewController *baseVc = [aspectInfo instance];
        [baseVc createUI];
        [baseVc initdata];
        [baseVc askNetwork];
    }error:&error];
    if (error)
    {
        Log(@"Load error: %@",error);
    }
}
@end

這么寫成Categorys其實不用BaseViewcontrol也是可以的;只要導入#import "UIViewController+Base.h" 文件就可以;優化不是一點點;

四丶Swift 實現

首先要先知道幾個東西;
1.swift 沒有load方法,使用initialize()
2.@convention關鍵字的作用:
2.1 修飾 Swift 中的函數類型,調用 C 的函數時候,可以傳入修飾過 @convention(c) 的函數類型,匹配 C 函數參數中的函數指針。
2.2 修飾 Swift 中的函數類型,調用 Objective-C 的方法時候,可以傳入修飾過 @convention(block) 的函數類型,匹配 Objective-C 方法參數中的 block 參數
3.unsafeBitCast
unsafeBitCast是非常危險的操作,它會將一個指針指向的內存強制按位轉換為目標的類型。因為這種轉換是在Swift的類型管理之外進行的,因此編譯器無法確保得到的類型是否確實正確,你必須明確地知道你在做什么

4.需要把原先填寫block的參數,轉成AnyObject

具體代碼:

override public class func initialize() {
    /*
     @convention
     1. 修飾 Swift 中的函數類型,調用 C 的函數時候,可以傳入修飾過 @convention(c) 的函數類型,匹配 C 函數參數中的函數指針。
     2. 修飾 Swift 中的函數類型,調用 Objective-C 的方法時候,可以傳入修飾過 @convention(block) 的函數類型,匹配 Objective-C 方法參數中的 block 參數
     */
    let block: @convention(block) (AnyObject!) -> Void = {
        info in
        let aspectInfo = info as! AspectInfo
        
        let control = aspectInfo.instance()
        #需要判類,
        if let myVc = control as? BaseViewController{
            myVc.customView()
            myVc.createUI()
            myVc.askNetwork()
        }
    }
    #block轉AnyObject
    let blobj: AnyObject = unsafeBitCast(block, to: AnyObject.self)
    do {
        let originalSelector = NSSelectorFromString("viewDidLoad")
       #在viewDidLoad之后調用
        try UIViewController.aspect_hook(originalSelector, with: .positionBefore, usingBlock: blobj)
        
    } catch  {
        print("error = \(error)")
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容