iOS 中的数组
source link: https://kingcos.me/posts/2020/array_in_ios/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Preface
数组,是我们在开发中经常使用的数据结构,其使用一段连续的内存空间存储。在 Obj-C 中,数组的类型分为 NSArray
不可变数组
Objective-C
NSArray & NSMutableArray
我们都知道,NSArray
是 Obj-C 中的不可变数组,而 NSMutableArray
是 Obj-C 的可变数组。这里我将 Obj-C 中几乎所有可能涉及到的数组对象,进行尝试打印其类别信息:
NSLog(@"%@", [[NSMutableArray alloc] class]); // __NSPlaceholderArray
NSLog(@"%@", [[NSArray alloc] class]); // __NSPlaceholderArray
NSLog(@"%@", [[[NSArray alloc] class] superclass]); // NSMutableArray
NSLog(@"%@", [[[[NSArray alloc] class] superclass] superclass]); // NSArray
NSLog(@"%@", [[[[[NSArray alloc] class] superclass] superclass] superclass]); // NSObject
NSLog(@"%@", [[NSArray array] class]); // __NSArray0
NSLog(@"%@", [[[NSArray alloc] init] class]); // __NSArray0
NSLog(@"%@", [[[[NSArray alloc] init] class] superclass]); // NSArray
NSLog(@"%@", [[NSMutableArray array] class]); // __NSArrayM
NSLog(@"%@", [[[NSMutableArray array] class] superclass]); // NSMutableArray
NSLog(@"%@", [@[@1] class]); // __NSSingleObjectArrayI
NSLog(@"%@", [[@[@1] class] superclass]); // NSArray
NSLog(@"%@", [@[@1, @2] class]); // __NSArrayI
NSLog(@"%@", [[@[@1, @2] class] superclass]); // NSArray
NSMutableArray *arr = [NSMutableArray array];
NSLog(@"%@", [arr class]); // __NSArrayM
[arr addObject:@1];
NSLog(@"%@", [arr class]); // __NSArrayM
由以上结果,我们可得出下图的继承树:
显而易见,NSArray
和 NSMutableArray
均属于类簇(Class Cluster),Obj-C 中所广泛使用的一种抽象工厂设计模式。这种设计使得类型对外暴露的接口得到统一,隐藏内部的具体实现类。
__NSPlacehodlerArray
__NSPlacehodlerArray
顾名思义即「占位」数组。无论我们要创建 NSArray
还是 NSMutableArray
,当调用 alloc
时,均返回了 __NSPlaceholderArray
类型的对象:
NSLog(@"%@", [[NSMutableArray alloc] class]); // __NSPlaceholderArray
NSLog(@"%@", [[NSArray alloc] class]); // __NSPlaceholderArray
而每次使用的 __NSPlaceholderArray
id arr1 = [NSArray alloc];
id arr2 = [NSArray alloc];
id arr3 = [NSArray alloc];
id arr4 = [NSArray alloc];
id arr5 = [NSArray alloc];
id marr1 = [NSMutableArray alloc];
id marr2 = [NSMutableArray alloc];
id marr3 = [NSMutableArray alloc];
id marr4 = [NSMutableArray alloc];
id marr5 = [NSMutableArray alloc];
// 0x7fff90a905b8 - 0x7fff90a905b8 - 0x7fff90a905b8 - 0x7fff90a905b8 - 0x7fff90a905b8
NSLog(@"%p - %p - %p - %p - %p", arr1, arr2, arr3, arr4, arr5);
// 0x7fff90a905c8 - 0x7fff90a905c8 - 0x7fff90a905c8 - 0x7fff90a905c8 - 0x7fff90a905c8
NSLog(@"%p - %p - %p - %p - %p", marr1, marr2, marr3, marr4, marr5);
// 0x7fff90a905c8 - 0x7fff90a905b8 == 16
那么问题来了,__NSPlaceholderArray
内部是如何区分将要初始化的数组类型呢?
For historical reasons,
alloc
invokesallocWithZone:
.
根据官方文档中的提示,alloc
方法由于历史原因,内部仍然调用了 allocWithZone:.
。我们通过 LLDB breakpoint set --name "+[NSArray allocWithZone:]"
打个断点
CoreFoundation`+[NSArray allocWithZone:]:
-> 0x7fff38ecb971 <+0>: pushq %rbp
...
0x7fff38ecb9e8 <+119>: jmp 0x7fff38ecba0c ; __NSArrayImmutablePlaceholder
...
0x7fff38ecba02 <+145>: jmp 0x7fff38ee4a8d ; __NSArrayMutablePlaceholder
CoreFoundation`__NSArrayImmutablePlaceholder:
-> 0x7fff38ecba0c <+0>: leaq 0x57bc4ba5(%rip), %rax ; ___immutablePlaceholderArray
0x7fff38ecba13 <+7>: retq
CoreFoundation`__NSArrayMutablePlaceholder:
-> 0x7fff38ee4a8d <+0>: leaq 0x57babb34(%rip), %rax ; ___mutablePlaceholderArray
0x7fff38ee4a94 <+7>: retq
Swift
Array
Reference
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK