最近在公司做崩溃防御,参考了safeKit很多源码,利用runtime处理一些我们编程犯得低级错误很有用处,可惜的是作者2年前就弃坑了,其中很多commit都是很有用的。随便这个机会把OC底层知识回顾下,并做下记录和整理。
NSArray *array = [NSArray alloc] init];
NSLog(@"array -- 类: %@", [array class]);
打印的时候发现 array -- 类: __NSArray0
__NSArray0 这个其实是NSArray的子类对象,array常见的子类对象
只有一个对象的数组 __NSSingleObjectArrayI
空数组 __NSArray0
有对象的数组 __NSArrayI
可变数组
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的时候,一定要区分好。 另外
ios11 以前
objectAtIndex:
ios11 以后
objectAtIndexedSubscript:
分析下这行基础的代码
NSArray重写了+ (id)allocWithZone:(struct _NSZone *)zone方法,在方法内部,如果调用类为NSArray则直接返回全局变量___immutablePlaceholderArray,如果调用类为NSMUtableArray则直接返回全局变量___mutablePlaceholderArray。
也就是调用[NSArray alloc]或者[NSMUtableArray alloc]得到的仅仅是两个占位指针,类型为__NSPlaceholderArray.
在调用了alloc的基础上,不论是NSArray或NSMutableArray都必定要继续调用某个initXXX方法,而实际上调用的是__NSPlaceholderArray的initXXX.在这个initXXX方法内部,如果self == ___immutablePlaceholderArray就会重新构造并返回__NSArrayI 对象,如果self == ___mutablePlaceholderArray就会重新构造并返回_NSArrayM对象.
总结来说,对于NSArray和NSMutableArray,alloc时拿到的仅仅是个占位对象,init后才得到真实的子类对象.
参考文献:
https://www.jianshu.com/p/66f8410c6bbc
后续不断更新..
网友评论