最近在公司做崩潰防御,參考了safeKit很多源碼,利用runtime處理一些我們編程犯得低級錯誤很有用處,可惜的是作者2年前就棄坑了,其中很多commit都是很有用的。隨便這個機會把OC底層知識回顧下,并做下記錄和整理。
NSArray *array = [NSArray alloc] init];
NSLog(@"array -- 類: %@", [array class]);
打印的時候發(fā)現(xiàn) array -- 類: __NSArray0
__NSArray0 這個其實是NSArray的子類對象,array常見的子類對象
只有一個對象的數(shù)組 __NSSingleObjectArrayI
空數(shù)組 __NSArray0
有對象的數(shù)組 __NSArrayI
可變數(shù)組
NSMutableArray __NSArrayM

image.png
NSArray *arr0 = @[];
NSArray *arrAlloc_0 = [[NSArray alloc] init];
NSLog(@"arr0 -- 類: %@", [arr0 class]);
NSLog(@"arrAlloc_0 -- 類: %@", [arrAlloc_0 class]);
NSArray *arr1 = [[NSArray alloc] initWithObjects:@"2", nil];
NSArray *arr1_1 = @[@"1"];
NSLog(@"arr1 -- 類: %@", [arr1 class]);
NSLog(@"arr1_1 -- 類: %@", [arr1_1 class]);
NSArray *arr2 = @[@"1",@"2"];
NSArray *arr3 = @[@"1",@"2", @"3"];
NSLog(@"arr2 -- 類: %@", [arr2 class]);
NSLog(@"arr3 -- 類: %@", [arr3 class]);
NSArray *arrPlaceholder = [NSArray alloc];
NSMutableArray *arrM_placehodler = [NSMutableArray alloc];
NSLog(@"arrPlaceholder -- 類: %@", [arrPlaceholder class]);
NSLog(@"arrM_placehodler -- 類: %@", [arrM_placehodler class]);
NSMutableArray *arrM = [NSMutableArray array];
NSLog(@"arrM -- 類: %@", [arrM class]);

image.png
因此在用runtime swizzle的時候,一定要區(qū)分好。 另外
ios11 以前
objectAtIndex:
ios11 以后
objectAtIndexedSubscript:
分析下這行基礎的代碼
NSArray重寫了+ (id)allocWithZone:(struct _NSZone *)zone方法,在方法內(nèi)部,如果調用類為NSArray則直接返回全局變量___immutablePlaceholderArray,如果調用類為NSMUtableArray則直接返回全局變量___mutablePlaceholderArray。
也就是調用[NSArray alloc]或者[NSMUtableArray alloc]得到的僅僅是兩個占位指針,類型為__NSPlaceholderArray.
在調用了alloc的基礎上,不論是NSArray或NSMutableArray都必定要繼續(xù)調用某個initXXX方法,而實際上調用的是__NSPlaceholderArray的initXXX.在這個initXXX方法內(nèi)部,如果self == ___immutablePlaceholderArray就會重新構造并返回__NSArrayI 對象,如果self == ___mutablePlaceholderArray就會重新構造并返回_NSArrayM對象.
總結來說,對于NSArray和NSMutableArray,alloc時拿到的僅僅是個占位對象,init后才得到真實的子類對象.
參考文獻:
http://www.itdecent.cn/p/66f8410c6bbc
后續(xù)不斷更新..