iOS依賴注入

源碼

依賴注入(Dependency Injection)這個詞,源于java,但在Cocoa框架中也是十分常見的。
舉例來說:
UIView的初始化方法initWithFrame

- (id)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;

這里的frame傳入值,就是所謂的依賴(Dependency),這個View實例化是根據(jù)frame注入實現(xiàn)的。
但這種用法有很大的局限性

  1. 我們不知道究竟依賴注入的屬性有哪些
  2. 不可能無限加長方法長度來滿足更多的依賴屬性

所以我們準備采用字典容器對NSObject類進行依賴注入擴展。

給NSObject類添加一個Category

@interface NSObject (XXXDependencyInjection)

- (nullable id)initWithParams:(nonnull NSDictionary *)params;
- (void)injection:(nonnull NSDictionary*)params;

@end

實現(xiàn)注入方法

- (id)initWithParams:(NSDictionary *)params
{
    self = [self init];
    if (self) {
        [self injection:params];
    }
    return self;
}

- (void)injection:(NSDictionary*)params
{
    [params.allKeys enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",[[obj substringToIndex:1] uppercaseString],[obj substringFromIndex:1]]);
        id value = [params objectForKey:obj];
        
        
        if ([self respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [self performSelector:selector withObject:value];
#pragma clang diagnostic pop
        }
        else
        {
            @try {
                [self setValue:value forKeyPath:obj];
            }
            @catch (NSException *exception) {
                NSLog(@"%@",exception);
                [exception raise];
            }
            @finally {
                
            }
        }
    }];
}

解釋

我們將需要注入的屬性,封裝到一個字典里,例如:

UIViewController* controller = [[UIViewController alloc] initWithParams:@{
                               @"title":@"測試",
                               @"view.backgroundColor":[UIColor whiteColor]
                                                                              }];

我們給這個VC注入了兩個屬性,一個是其title,一個是其View的backgroundColor屬性。
字典傳入以后,我們讀區(qū)params.allKeys進行遍歷,拼裝set+參數(shù)名的selector,這里用的是NSSelectorFromString方法:

SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",[[obj substringToIndex:1] uppercaseString],[obj substringFromIndex:1]]);

然后我們判斷實例是否可以響應這個set方法,如果可以,則給其賦值。

        if ([self respondsToSelector:selector]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
            [self performSelector:selector withObject:value];
#pragma clang diagnostic pop
        }

這里的三行clang宏是為了消除編譯器的內(nèi)存泄漏警告,這里因為我們進行了驗證,所以不會出現(xiàn)leak。

KVC實現(xiàn)跨實例賦值

我們注意到上例中還有一句給VC的View改變背景顏色

  @"view.backgroundColor":[UIColor whiteColor]

這里就用到了KVC的點語法特性,在我們判斷到實例不能響應if ([self respondsToSelector:selector])的時候,通過點語法,進行賦值

@try {
    [self setValue:value forKeyPath:obj];
}
@catch (NSException *exception) {
    NSLog(@"%@",exception);
   [exception raise];
}
@finally {

}

這里添加了異常捕獲,因為點語法對屬性名稱拼寫要求是全匹配,否則拋異常,所以要注意。

優(yōu)缺點

這樣改造過的init方法,優(yōu)點非常明顯,就是綁定更加集中便捷,如果使用的是storyboard則可以輕松實現(xiàn)前后端分離。
目前的缺點也很明顯,不能告訴開發(fā)者哪些屬性是必需依賴,另外還不能支持非對象屬性的賦值(已經(jīng)可以,改為setValueforkeyPath方法賦值),希望拋磚引玉,大家來改進這段代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • dependency injection 關(guān)于IOS依賴注入那些事 本文介紹的是另一個屎上最牛叉的ios開發(fā)新框架...
    十三億少女夢丶閱讀 9,990評論 1 44
  • 什么是依賴注入呢? 依賴注入(DI)是一種非常流行的設計模式在許多的語言之中,比如說Java和C#,但是它似乎并沒...
    木易林1閱讀 1,472評論 0 0
  • iOS 依賴注入 最近讀項目代碼的總結(jié)! 什么是依賴呢,會有什么問題呢?平時寫代碼,這種依賴的方式太常見了。 看代...
    楊柳小易閱讀 4,367評論 0 8
  • 要使用工具, 首先還是先來了解一下為什么要使用它? 而這里有一篇很好的文章說明為什么要進行依賴注入, 以及一些相關(guān)...
    貘鳴閱讀 6,498評論 3 12
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139

友情鏈接更多精彩內(nèi)容