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
的時候,就必須要重寫count
和objectAtIndex:
,重寫其它系統類的時候也要注意查閱官方文檔。
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,很容易發生循環引用的現象,而我們又很難去發現,所以不是在不得已的情況下,盡量不要使用這種方式。