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:@, nil];
NSArray *arr3 = [placeholder initWithObjects:@, @, 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:@, nil];
NSMutableArray *arr3 = [arr initWithObjects:@, @, nil];
NSMutableArray *arr4 = [arr initWithObjects:@, @, @, 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
}
结果:
-- ::05.902187+ ArrTest[:] ==(
, )
-- ::05.902476+ ArrTest[:] arr3: 0x60400024b100
-- ::05.902828+ ArrTest[:] arr3: 0x60400024b100
-- ::05.903073+ ArrTest[:] ==( )
-- ::05.903227+ ArrTest[:] arr3: 0x60400024b100
发现数组的地址不会发生改变,方法里对arr进行修改后,arr3也会发生改变;
所以如果处理数据时不希望arr3被影响,需要对其进行初始化或者copy就行;
5、__NSPlaceholderArray简单说明
对NSArray和NSMutableArray进行alloc时生成的都是__NSPlaceholderArray类,只有在init时才会返回是不可变或者可变数组。
这种情况如NSNumber、NSString都是这样,这就是类蔟(Class clusters)的设计模式。
iOS之NSArray类簇简介-(copy、mutableCopy导致程序crash)的更多相关文章
- iOS开发-retain/assign/strong/weak/copy/mutablecopy/autorelease区别
依旧本着尊重原创和劳动者的原则,将地址先贴在前面: http://www.cnblogs.com/nonato/archive/2013/11/28/3447162.html,作者Nonato 以下内 ...
- iOS开发-类簇(Class Cluster)
类簇(Class Cluster)是定义相同的接口并提供相同功能的一组类的集合,仅公开接口的抽象类也可以称之为类簇的公共类,每个具体类的接口有公共类的接口抽象化,并隐藏在簇的内部.这些类一般不能够直 ...
- iOS 关键词assign、strong、copy、weak、unsafe_unretained
关键词assign.strong.copy.weak.unsafe_unretained 影响: 是否开辟新的内存 是否有引用计数增加 strong 指向并拥有该对象.其修饰的对象引用计数会 +1,该 ...
- iOS - 类簇
类簇是在Objective-C中Foundation Framework中广泛使用的一种设计模式 1.发现类簇(Class Cluster)的踪迹 //*> 执行下面代码 id obj1 = [ ...
- iOS copy&mutableCopy理解
Copy&mutableCopy 通过copy方法可以创建可变或不可变对象的不可变副本,通过mutableCopy可以创建可变或不可变对象的可变副本. 拷贝分为浅拷贝和深拷贝: 浅拷贝:指 ...
- IOS 杂笔-1(为什么不继承类簇?)
答:首先,类簇是可以继承的,并不是不可以.例如,我们可以选择继承NSSting,但是此时你用你自己设定的类去调用NSSting的一些方法时,会存在无法实现的问题,这是为什么呢. 1.类簇里有很多私有的 ...
- iOS开发知识点:理解assign,copy,retain变strong
一..h和.m文件的变化说明 1.对于.h头文件,主要是将属性定义由retain变为strong @property (retain, nonatomic) 变为 @property (strong, ...
- OC 类簇与复合
OC 类簇与复合 类簇: 类簇是Foundation框架中广泛使用的设计模式.类簇将一些私有的.具体的子类组合在一个公共的.抽象的超类下面,以这种方法来组织类可以简化一个面向对象框架的公开架构,而又不 ...
- IOS atomic与nonatomic,assign,copy与retain的定义和区别
IOS atomic与nonatomic,assign,copy与retain的定义和区别 atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作. ...
随机推荐
- jdk8中map新增的merge方法介绍
1.Map.merge方法介绍 jdk8对于许多常用的类都扩展了一些面向函数,lambda表达式,方法引用的功能,使得java面向函数编程更为方便.其中Map.merge方法就是其中一个,merge方 ...
- 单独编译和使用webrtc音频回声消除模块(附完整源码+测试音频文件)
单独编译和使用webrtc音频降噪模块(附完整源码+测试音频文件) 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件) 说实话很不想写这篇文章,因为这和我一贯推崇的最好全部编译并使用w ...
- Android中的第一个NDK的例子
前几天研究了JNI技术后,想在Android上试一试研究结果,查阅了很多资料后,总结如下步骤: 首先来看一下什么是NDK NDK 提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动 ...
- Python 让文件代码支持汉字
默认使用ASCII编码,改成utf8 #!/usr/bin/env python # -*- coding:utf8 -*- #coding:utf-8
- NX二次开发-UFUN获取一个图层类别的tag UF_LAYER_ask_category_tag
NX11+VS2013 #include <uf.h> #include <uf_ui.h> #include <uf_layer.h> UF_initialize ...
- nlp总结
中科院nlpir和海量分词(http://www.hylanda.com/)是收费的. hanlp:推荐基于CRF的模型的实现~~要看语料,很多常用词会被分错,所以需要词库支撑.目前最友好的开源工具包 ...
- DLL注入技术之劫持进程创建注入
劫持进程创建注入原理是利用Windows系统中CreateProcess()这个API创建一个进程,并将第6个参数设为CREATE_SUSPENDED,进而创建一个挂起状态的进程,利用这个进程状态进行 ...
- scrapy-redis + Bloom Filter分布式爬取tencent社招信息
scrapy-redis + Bloom Filter分布式爬取tencent社招信息 什么是scrapy-redis 什么是 Bloom Filter 为什么需要使用scrapy-redis + B ...
- Date转换为LocalDateTime
一.在Java 8中将Date转换为LocalDateTime 方法1: 将Date转换为LocalDatetime,我们可以使用以下方法: 1.从日期获取ZonedDateTime并使用其方法toL ...
- json、pickle和base64
json.dumps() 用于将dict类型的数据转成str,因为如果直接将dict类型的数据写入json文件中会发生报错,因此在将数据写入时需要用到该函数. json.dump() 用于将dict类 ...