iOS之NSArray类簇简介-(copy、mutableCopy导致程序crash)
1、前言
开发时常常用数组对数据进行处理,对NSMutableArray进行操作时经常导致程序崩溃,特研究一下NSArray的类簇!涉及__NSPlaceholderArray、__NSArray0、__NSSingleObjectArrayI、__NSArrayI、__NSArrayM相关类。
2、分析NSArray
2.1、创建不可变出租
NSArray *placeholder = [NSArray alloc]; NSArray *arr1 = [placeholder init]; NSArray *arr2 = [placeholder initWithObjects:@0, nil]; NSArray *arr3 = [placeholder initWithObjects:@0, @1, nil]; NSLog(@"arr: %s", object_getClassName([NSArray array])); // arr: __NSArray0 NSLog(@"placeholder: %s", object_getClassName(placeholder)); // placeholder: __NSPlaceholderArray NSLog(@"arr1: %s", object_getClassName(arr1)); // arr1: __NSArray0 NSLog(@"arr2: %s", object_getClassName(arr2)); // arr2: __NSSingleObjectArrayI NSLog(@"arr3: %s", object_getClassName(arr3)); // arr3: __NSArrayI
可以看出 [NSArray array] 等同于[ [NSArray alloc] init],都是空元素类 __NSArray0;
__NSPlaceholderArray:alloc时的对象先统一为这个类对象,不可变数组也是这样;
__NSArray0:数组init后没有元素;
__NSSingleObjectArrayI:数组只有一个元素;
__NSArrayI:不可变数组切元素在一个以上;
2.2、分别对arr1、arr2、arr3进行copy和mutableCopy操作:
NSLog(@"arr1: %s", object_getClassName([arr1 copy])); // arr1: __NSArray0 NSLog(@"arr2: %s", object_getClassName([arr2 copy])); // arr2: __NSSingleObjectArrayI NSLog(@"arr3: %s", object_getClassName([arr3 copy])); // arr3: __NSArrayI NSLog(@"================="); NSLog(@"arr1: %s", object_getClassName([arr1 mutableCopy])); // arr1: __NSArrayM NSLog(@"arr2: %s", object_getClassName([arr2 mutableCopy])); // arr2: __NSArrayM NSLog(@"arr3: %s", object_getClassName([arr3 mutableCopy])); // arr3: __NSArrayM
对不可变数组进行copy不会改变类名,但mutableCopy都会变成可变数组;
3、分析NSMutableArray
3.1、创建不可变数组
NSMutableArray *arr = [NSMutableArray alloc]; NSMutableArray *arr1 =[arr init]; NSMutableArray *arr2 = [arr initWithObjects:@0, nil]; NSMutableArray *arr3 = [arr initWithObjects:@0, @1, nil]; NSMutableArray *arr4 = [arr initWithObjects:@0, @1, @2, nil]; NSLog(@"arr: %s", object_getClassName([NSMutableArray array])); // arr: __NSArrayM NSLog(@"placeholder: %s", object_getClassName(arr)); // placeholder: __NSPlaceholderArray NSLog(@"arr1: %s", object_getClassName(arr1)); // arr1: __NSArrayM NSLog(@"arr2: %s", object_getClassName(arr2)); // arr2: __NSArrayM NSLog(@"arr3: %s", object_getClassName(arr3)); // arr3: __NSArrayM
可以看出 [NSMutableArray array] 等同于[ [NSMutableArray alloc] init],都是可变数组类 __NSArrayM;
__NSPlaceholderArray:alloc时的对象先统一为这个类对象;
__NSArrayM:可变数组类;
3.2、分别对arr1、arr2、arr3进行copy和mutableCopy操作:
NSLog(@"arr1: %s", object_getClassName([arr1 copy])); // arr1: __NSArray0 NSLog(@"arr2: %s", object_getClassName([arr2 copy])); // arr2: __NSSingleObjectArrayI NSLog(@"arr3: %s", object_getClassName([arr3 copy])); // arr3: __NSArrayI NSLog(@"================="); NSLog(@"arr1: %s", object_getClassName([arr1 mutableCopy])); // arr1: __NSArrayM NSLog(@"arr2: %s", object_getClassName([arr2 mutableCopy])); // arr2: __NSArrayM NSLog(@"arr3: %s", object_getClassName([arr3 mutableCopy])); // arr3: __NSArrayM
对不可变数组进行copy会改变为对应的不可变数组类名,但mutableCopy不会改变数组;
4、方法持有数组
NSLog(@"==%@",arr3); NSLog(@"arr3: %p", arr3); // arr2: 0x608000014050 [self exchangeMArr:arr3]; NSLog(@"==%@",arr3); NSLog(@"arr3: %p", arr3); // arr2: 0x608000014050
- (void)exchangeMArr:(NSMutableArray *)arr{ NSMutableArray *arr1 = arr; [arr1 removeLastObject]; NSLog(@"arr3: %p", arr1); // arr2: 0x608000014050 }
结果:
2018-06-11 14:52:05.902187+0800 ArrTest[5672:265513] ==( 0, 1 ) 2018-06-11 14:52:05.902476+0800 ArrTest[5672:265513] arr3: 0x60400024b100 2018-06-11 14:52:05.902828+0800 ArrTest[5672:265513] arr3: 0x60400024b100 2018-06-11 14:52:05.903073+0800 ArrTest[5672:265513] ==( 0 ) 2018-06-11 14:52:05.903227+0800 ArrTest[5672:265513] arr3: 0x60400024b100
发现数组的地址不会发生改变,方法里对arr进行修改后,arr3也会发生改变;
所以如果处理数据时不希望arr3被影响,需要对其进行初始化或者copy就行;
5、__NSPlaceholderArray简单说明
对NSArray和NSMutableArray进行alloc时生成的都是__NSPlaceholderArray类,只有在init时才会返回是不可变或者可变数组。
这种情况如NSNumber、NSString都是这样,这就是类蔟(Class clusters)的设计模式。