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

一丶介紹

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

AOP主要實(shí)現(xiàn)的目的是針對(duì)業(yè)務(wù)處理過程中的切面進(jìn)行提取捡多,它所面對(duì)的是處理過程中的某個(gè)步驟或階段蓖康,以獲得邏輯過程中各部分之間低耦合性的隔離效果。

[1] 比如我們最常見的就是日志記錄了垒手,舉個(gè)例子蒜焊,我們現(xiàn)在提供一個(gè)服務(wù)查詢學(xué)生信息的,但是我們希望記錄有誰進(jìn)行了這個(gè)查詢科贬。如果按照傳統(tǒng)的OOP的實(shí)現(xiàn)的話泳梆,那我們實(shí)現(xiàn)了一個(gè)查詢學(xué)生信息的服務(wù)接口(StudentInfoService)和其實(shí)現(xiàn)類(StudentInfoServiceImpl.java),同時(shí)為了要進(jìn)行記錄的話唆迁,那我們?cè)趯?shí)現(xiàn)類(StudentInfoServiceImpl.java)中要添加其實(shí)現(xiàn)記錄的過程鸭丛。這樣的話竞穷,假如我們要實(shí)現(xiàn)的服務(wù)有多個(gè)呢唐责?那就要在每個(gè)實(shí)現(xiàn)的類都添加這些記錄過程。這樣做的話就會(huì)有點(diǎn)繁瑣瘾带,而且每個(gè)實(shí)現(xiàn)類都與記錄服務(wù)日志的行為緊耦合鼠哥,違反了面向?qū)ο蟮囊?guī)則。那么怎樣才能把記錄服務(wù)的行為與業(yè)務(wù)處理過程中分離出來呢看政?看起來好像就是查詢學(xué)生的服務(wù)自己在進(jìn)行朴恳,但卻是背后日志記錄對(duì)這些行為進(jìn)行記錄,并且查詢學(xué)生的服務(wù)不知道存在這些記錄過程允蚣,這就是我們要討論AOP的目的所在于颖。AOP的編程,好像就是把我們?cè)谀硞€(gè)方面的功能提出來與一批對(duì)象進(jìn)行隔離嚷兔,這樣與一批對(duì)象之間降低了耦合性森渐,可以就某個(gè)功能進(jìn)行編程。
---摘自百度百科

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

- (void)viewDidLoad
{
    [super viewDidLoad];
    //創(chuàng)建視圖代碼
    [self createUI];
   //初始化數(shù)據(jù)
    [self initdata];
   //網(wǎng)絡(luò)請(qǐng)求
    [self askNetwork];
}

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

二丶Aspects的介紹

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

主要還是用到oc神奇的runtime機(jī)制,動(dòng)態(tài)的改變了 selector 和 IMP 的對(duì)應(yīng)關(guān)系;(此圖并非原創(chuàng))

Paste_Image.png

主要用到2個(gè)方法:

+ (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 執(zhí)行的時(shí)機(jī)

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應(yīng)用

@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其實(shí)不用BaseViewcontrol也是可以的;只要導(dǎo)入#import "UIViewController+Base.h" 文件就可以;優(yōu)化不是一點(diǎn)點(diǎn);

四丶Swift 實(shí)現(xiàn)

首先要先知道幾個(gè)東西;
1.swift 沒有l(wèi)oad方法,使用initialize()
2.@convention關(guān)鍵字的作用:
2.1 修飾 Swift 中的函數(shù)類型冒晰,調(diào)用 C 的函數(shù)時(shí)候同衣,可以傳入修飾過 @convention(c) 的函數(shù)類型,匹配 C 函數(shù)參數(shù)中的函數(shù)指針壶运。
2.2 修飾 Swift 中的函數(shù)類型耐齐,調(diào)用 Objective-C 的方法時(shí)候,可以傳入修飾過 @convention(block) 的函數(shù)類型,匹配 Objective-C 方法參數(shù)中的 block 參數(shù)
3.unsafeBitCast
unsafeBitCast是非常危險(xiǎn)的操作埠况,它會(huì)將一個(gè)指針指向的內(nèi)存強(qiáng)制按位轉(zhuǎn)換為目標(biāo)的類型耸携。因?yàn)檫@種轉(zhuǎn)換是在Swift的類型管理之外進(jìn)行的,因此編譯器無法確保得到的類型是否確實(shí)正確询枚,你必須明確地知道你在做什么

4.需要把原先填寫block的參數(shù),轉(zhuǎn)成AnyObject

具體代碼:

override public class func initialize() {
    /*
     @convention
     1. 修飾 Swift 中的函數(shù)類型违帆,調(diào)用 C 的函數(shù)時(shí)候,可以傳入修飾過 @convention(c) 的函數(shù)類型金蜀,匹配 C 函數(shù)參數(shù)中的函數(shù)指針刷后。
     2. 修飾 Swift 中的函數(shù)類型,調(diào)用 Objective-C 的方法時(shí)候渊抄,可以傳入修飾過 @convention(block) 的函數(shù)類型尝胆,匹配 Objective-C 方法參數(shù)中的 block 參數(shù)
     */
    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轉(zhuǎn)AnyObject
    let blobj: AnyObject = unsafeBitCast(block, to: AnyObject.self)
    do {
        let originalSelector = NSSelectorFromString("viewDidLoad")
       #在viewDidLoad之后調(diào)用
        try UIViewController.aspect_hook(originalSelector, with: .positionBefore, usingBlock: blobj)
        
    } catch  {
        print("error = \(error)")
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市护桦,隨后出現(xiàn)的幾起案子含衔,更是在濱河造成了極大的恐慌,老刑警劉巖二庵,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贪染,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡催享,警方通過查閱死者的電腦和手機(jī)杭隙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來因妙,“玉大人痰憎,你說我怎么就攤上這事∨屎” “怎么了铣耘?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)以故。 經(jīng)常有香客問我蜗细,道長(zhǎng),這世上最難降的妖魔是什么怒详? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任炉媒,我火速辦了婚禮,結(jié)果婚禮上棘利,老公的妹妹穿的比我還像新娘橱野。我一直安慰自己筝尾,他們只是感情好噪沙,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布机蔗。 她就那樣靜靜地躺著,像睡著了一般兑宇。 火紅的嫁衣襯著肌膚如雪氢架。 梳的紋絲不亂的頭發(fā)上鹏溯,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天旺罢,我揣著相機(jī)與錄音,去河邊找鬼奕扣。 笑死薪鹦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的惯豆。 我是一名探鬼主播池磁,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼楷兽!你這毒婦竟也來了地熄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤芯杀,失蹤者是張志新(化名)和其女友劉穎端考,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體揭厚,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡却特,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筛圆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片裂明。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖顽染,靈堂內(nèi)的尸體忽然破棺而出漾岳,到底是詐尸還是另有隱情轰绵,我是刑警寧澤粉寞,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站左腔,受9級(jí)特大地震影響唧垦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜液样,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一振亮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鞭莽,春花似錦坊秸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春星瘾,著一層夾襖步出監(jiān)牢的瞬間走孽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工琳状, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留磕瓷,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓念逞,卻偏偏與公主長(zhǎng)得像困食,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子翎承,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,280評(píng)論 25 707
  • 前言 在“Runtime病院”住院的后兩天陷舅,分析了一下AOP的實(shí)現(xiàn)原理∩蠖矗“出院”后莱睁,發(fā)現(xiàn)Aspect庫還沒有詳細(xì)分...
    一縷殤流化隱半邊冰霜閱讀 18,640評(píng)論 34 165
  • 對(duì)沒有辨識(shí)力的人來說,自我的爬山和無私的爬山看上去可能都一樣芒澜,都是一步一步地往上爬仰剿;呼吸的速度也一樣;疲累的時(shí)候都...
    余江燕閱讀 215評(píng)論 0 0
  • 酒瘋子 /深山老林(千年桃妖) 見酒沒命 遇酒即醉 有時(shí)嗨飲 沒時(shí) 一朝 心荒荒 即便今日囊中羞 借錢也要打幾兩 ...
    深山老林千年桃妖閱讀 155評(píng)論 2 1
  • 記憶中對(duì)手工制品最開始的印象大概就是老物件吧痴晦,結(jié)實(shí)南吮,耐用。長(zhǎng)大后發(fā)現(xiàn)原來手工制品意味著更多的money誊酌,是因?yàn)楝F(xiàn)在...
    大米996閱讀 255評(píng)論 0 1