編寫高質量ios代碼4

1. 以“類族模式”隱藏實現的細節

在我們平時的代碼構建中,經常會用到繼承。在類的繼承關系以及方法的定義上有很多需要注意。
以下幾點需要引起注意:

  • 在設計業務邏輯的時候,一定要考慮繼承類的分層設計,將方法的實現和業務相對應,以降低類與類之間的耦合性。
  • 在系統的框架中有很多的類族,它們是類組中的抽象的基類。在使用該類族創建對象的時候會先分配一個繼承自該類的子類,然后由該子類實例化想要的實力對象,舉例說明;
id test = [[NSArray alloc]init];
if ([test class] == [NSArray class])
 {
            
 }

這段代碼的if 判斷條件永遠也不會成立,因為[test class][NSArray class]的父類,下面用代碼證明:

        MyArray * arr22 = (MyArray *)@[@1,@2,@3];
        MyArray1 * arr11 = (MyArray1 *)@[@1,@2];
        NSLog(@"%@",[arr22 class]);
        NSLog(@"%@",[arr11 class]);
        Father * father = [[Father alloc]init];
        Son * son = [[Son alloc]init];
        
        BOOL res = [father isKindOfClass:[NSObject class]];
        BOOL res1 = [father isKindOfClass:[Father class]];
        
        NSLog(@"res---%d",res);
        NSLog(@"res1---%d",res1);

        BOOL res2 = [son isKindOfClass:[NSObject class]];
        BOOL res3 = [son isKindOfClass:[Father class]];
        
        NSLog(@"res2---%d",res2);
        NSLog(@"res3---%d",res3);
        
        BOOL res4 = [father isMemberOfClass:[NSObject class]];
        BOOL res5 = [father isMemberOfClass:[Father class]];
        
        NSLog(@"res4---%d",res4);
        NSLog(@"res5---%d",res5);
        
        BOOL res6 = [son isMemberOfClass:[NSObject class]];
        BOOL res7 = [son isMemberOfClass:[Father class]];
        
        NSLog(@"res6---%d",res6);
        NSLog(@"res7---%d",res7);
        
        id temp = [[Son alloc]init];
        
        BOOL ress = ([Son class] == [temp class]);
        NSLog(@"%d",ress);
        
        id arr1 = [[NSArray alloc] init];
        BOOL ress1 = ([arr1 class] == [NSArray class]);
        NSLog(@"%d",ress1);
        
        NSLog(@"%@",[NSArray class]);
        NSLog(@"%@",[arr1 class]);
        
        BOOL ress2 = [arr1 isMemberOfClass:[NSArray class]];
        BOOL ress3 = [arr1 isKindOfClass:[NSArray class]];
        
        NSLog(@"%d",ress2);//0
        NSLog(@"%d",ress3);//1
        
        NSArray * arr2 = [[NSArray alloc]init];
        BOOL ress4 = ([arr2 class] == [NSArray class]);
        NSLog(@"%d",ress4);
        NSLog(@"%@",[arr2 class]);

打印結果:

打印結果

從打印結果我們可以清楚地看出,類之間的繼承關系。

  • 我們在重寫系統類的時候一定要注意查閱官方文檔,看哪些方法是必須要實現的。例如當我們重寫NSArray的時候,就必須要重寫countobjectAtIndex:,重寫其它系統類的時候也要注意查閱官方文檔。

2.在類中只用關聯對象存放自定義的數據

當我們在開發中遇到在某些類中,添加屬性比較困難的時候,就可以使用關聯對象。
關聯對象是屬于運行時機制里面的。
下面我們來看一下基本用法:

  • 設定關聯對象
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

id object:當前對象
const void *key:所關聯對象所對應的鍵
id value:要關聯的對象
objc_AssociationPolicy policy:關聯對象存儲策略

  • 獲取關聯對象
id objc_getAssociatedObject(id object, const void *key)

id object:當前對象
const void *key:所關聯對象所對應的鍵

  • 移除指定對象的全部關聯對象
void objc_removeAssociatedObjects(id object)

下面看一段代碼:

static void *key = @"xiao";
- (void)viewDidLoad {
    [super viewDidLoad];

    void (^block)(NSInteger) = ^(NSInteger num){
    
        NSLog(@"%ld",(long)num);
    };
    objc_setAssociatedObject(self, key, block, OBJC_ASSOCIATION_COPY);
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [self test1];
}

- (void)test1{

    void (^block)(NSInteger) = objc_getAssociatedObject(self, key);
    
    block(90);
}

這樣我們就給當前的控制器添加了一個block屬性,其實我們完全可以用屬性去包裝block,當我們無法給當前的抽象類添加屬性的時候,我們其實就沒有必要再創建該抽象類的實例,然后再去繼承屬性,這樣會增加代碼量,這樣關聯對象,可以節省代碼量(在不方便創建屬性的情況下),同時也可以優化代碼結構。
注:使用這種方式其實也是有一定的弊端的,首先你關聯的對象,內部銀土其他參數的時候,比如引用block,很容易發生循環引用的現象,而我們又很難去發現,所以不是在不得已的情況下,盡量不要使用這種方式。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容