mutableCopy与copy在面试中的那些坑你知道吗?
来源:互联网 发布:爱丁堡商学院申请 知乎 编辑:程序博客网 时间:2024/06/11 00:14
最近听到朋友谈论在面试中被面试官通过基础知识深挖狂虐的事情,心中有些不忿,决定推出一系列基础知识重温的文章,在方便自己复习的同时,希望和大家一块进步。
这一篇文章主要对mutableCopy,copy进行复习,解惑。iOS中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutableCopying 协议的类才可以发送mutableCopy消息。假如发送了一个没有遵守上诉两协议而发送 copy或者 mutableCopy,那么就会发生异常。但是默认的ios类并没有遵守这两个协议。如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法,如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法。我们用如下代码进行验证:
@interface Person : NSObject@property (nonatomic,strong)NSString *name;@property (nonatomic,assign)NSInteger age;@end
Person *jack = [Person new]; jack.name = @"jack"; jack.age = 1; NSLog(@"jack:%p",jack); NSLog(@"jack.name:%p",jack.name); Person *lucy = [jack copy]; NSLog(@"lucy:%p",lucy); NSLog(@"lucy.name:%p",lucy.name);
在运行的时候发生崩溃,崩溃信息如下:
2017-04-30 16:51:56.373 interviewDemo[13770:2541374] -[Person copyWithZone:]: unrecognized selector sent to instance 0x60000003e8002017-04-30 16:51:56.434 interviewDemo[13770:2541374] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person copyWithZone:]: unrecognized selector sent to instance 0x60000003e800'
我们发现Person类没有遵守NSCopying协议,如果对其实例对象执行copy操作就会出现崩溃。由于没有遵守NSMutableCopying协议同样对其实例对象执行mutableCopy操作同样会崩溃。
iOS中遵守NSCopying
协议的类有:NSString,NSValue,NSArray,NSDictionary,NSSet
;遵守NSMutableCopying
协议的类有: NSString,NSValue,NSArray,NSDictionary,NSSet
当然了别忘了这些类的子类哦。
接下来为大家说一下copy和retain的区别。copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化。copy减少对象对上下文的依赖。 retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝。
注意:声明属性时用strong或者retain效果是一样的,我这里在ARC环境下使用strong和copy进行验证比较,示例代码如下:
strong代码
@interface Person : NSObject@property (nonatomic,strong)NSString *name;@property (nonatomic,assign)NSInteger age;@property (nonatomic,strong)Person *child;@end
Person *xiaoJack = [Person new]; xiaoJack.name = @"小jack"; Person *jack = [Person new]; jack.name = @"jack"; jack.child =xiaoJack; NSLog(@"xiaoJack %p",xiaoJack); NSLog(@"jack.child %p",jack.child); NSLog(@"xiaoJack retainCount %@",[xiaoJack valueForKey:@"retainCount"]);
运行结果如下:
2017-04-30 18:12:17.995 interviewDemo[14122:2595610] xiaoJack 0x60800002fd202017-04-30 18:12:17.995 interviewDemo[14122:2595610] jack.child 0x60800002fd202017-04-30 18:12:17.996 interviewDemo[14122:2595610] xiaoJack retainCount 2
我们发现xiaoJack 和jack.child指向的相同的内存地址,而且xiaoJack的retainCount为2,说明 strong/retain操作是指针拷贝。
copy代码:
@interface Person : NSObject<NSCopying>@property (nonatomic,copy)NSString *name;@property (nonatomic,assign)NSInteger age;@property (nonatomic,copy)Person *child;-(id)copyWithZone:(NSZone *)zone;@end
Person *xiaoJack = [Person new]; xiaoJack.name = @"小jack"; Person *jack = [Person new]; jack.name = @"jack"; jack.child =xiaoJack; NSLog(@"xiaoJack %p",xiaoJack); NSLog(@"jack.child %p",jack.child); NSLog(@"xiaoJack retainCount %@",[xiaoJack valueForKey:@"retainCount"]);
运行结果如下:
2017-04-30 18:15:26.720 interviewDemo[14164:2598814] xiaoJack 0x608000037be02017-04-30 18:15:26.720 interviewDemo[14164:2598814] jack.child 0x60800003e2802017-04-30 18:15:26.721 interviewDemo[14164:2598814] xiaoJack retainCount 1
我们可以发现xiaoJack指向的内存地址和jack.child指向的内存地址不一样,并且xiaoJack的retainCount仍然为1 。说明copy操作是创建一个新对象。
经过验证,用户自定义类实现NSCopying协议的会对对象进行复制创建一个新对象,而系统提供的实现了NSCopying协议的,确实指针copy。
我的代码如下:
-(id)copyWithZone:(NSZone *)zone{ ClassA *copy = [[[self class] allocWithZone:zone] init]; return copy;}
欢迎大家一块讨论
在验证copy与retain/strong 区别时候发现NSString,NSNumber属于常量类型,retainCount显示不受retain,release影响,是一个我们预期意外的值,不能做为参考使用。
下面是我从网上找来的一张图片
根据苹果官方的定义,iOS系统定义的对象分为系统的非容器类对象和系统的容器类对象。系统的非容器类对象有NSString,NSNumber(不支持NSCopying,NSMutableCopying)。对于NSString的,copy,mutableCopy执行的操作如上表所示,我这里已经验证过了。但是对于系统的容器类对象NSArray,NSDictionary,NSSet,其元素对象始终是指针复制。我这里很有必要为大家进行验证一下,
1,Person不支持NSCopying
@interface Person : NSObject@property (nonatomic,copy)NSString *name;@property (nonatomic,assign)NSInteger age;@property (nonatomic,copy)Person *child;@end
Person *jack = [Person new]; jack.name = @"jack"; jack.age = 1; Person *lucy = [Person new]; lucy.name = @"lucy"; lucy.age = 2; NSArray *array1 = @[jack,lucy]; NSArray *array2 = [array1 copy]; NSLog(@"array1 retainCount %@",[array1 valueForKey:@"retainCount"]); NSLog(@"array1 %p",array1); for (int i =0; i<array1.count; i++) { Person *person = array1[i]; NSLog(@"person:%p",person); } NSLog(@"***********"); NSLog(@"array2 %p",array2); for (int i =0; i<array2.count; i++) { Person *person = array2[i]; NSLog(@"person:%p",person); } NSLog(@"***********");
运行结果如下:
2017-05-01 08:42:32.993 interviewDemo[14956:2719378] array1 retainCount ( 2, 2)2017-05-01 08:42:32.994 interviewDemo[14956:2719378] array1 0x600000226d402017-05-01 08:42:32.994 interviewDemo[14956:2719378] person:0x600000226d802017-05-01 08:42:32.994 interviewDemo[14956:2719378] person:0x600000226d602017-05-01 08:42:32.994 interviewDemo[14956:2719378] ***********2017-05-01 08:42:32.994 interviewDemo[14956:2719378] array2 0x600000226d402017-05-01 08:42:32.995 interviewDemo[14956:2719378] person:0x600000226d802017-05-01 08:42:32.995 interviewDemo[14956:2719378] person:0x600000226d602017-05-01 08:42:32.995 interviewDemo[14956:2719378] ***********
发现array1,array2指向同样的内存地址,array1,array2内的元素也指向同样的内存地址。array1的retainCount操作显示的是内部元素的retainCount都为2,可见内部元素进行了strong/retain操作。
2,Person支持NSCopying
@interface Person : NSObject<NSCopying>@property (nonatomic,copy)NSString *name;@property (nonatomic,assign)NSInteger age;@property (nonatomic,copy)Person *child;-(id)copyWithZone:(NSZone *)zone;@end@implementation Person-(id)copyWithZone:(NSZone *)zone{ Person *copy = [[[self class] allocWithZone:zone] init]; copy->_name = [_name copy]; copy->_age = _age; return copy;}@end
Person *jack = [Person new]; jack.name = @"jack"; jack.age = 1; Person *lucy = [Person new]; lucy.name = @"lucy"; lucy.age = 2; NSArray *array1 = @[jack,lucy]; NSArray *array2 = [array1 copy]; NSLog(@"array1 retainCount %@",[array1 valueForKey:@"retainCount"]); NSLog(@"array1 %p",array1); for (int i =0; i<array1.count; i++) { Person *person = array1[i]; NSLog(@"person:%p",person); } NSLog(@"***********"); NSLog(@"array2 %p",array2); for (int i =0; i<array2.count; i++) { Person *person = array2[i]; NSLog(@"person:%p",person); } NSLog(@"***********");
运行结果如下:
2017-05-01 09:29:24.575 interviewDemo[15094:2757902] array1 retainCount ( 2, 2)2017-05-01 09:29:24.575 interviewDemo[15094:2757902] array1 0x6080000339202017-05-01 09:29:24.575 interviewDemo[15094:2757902] person:0x6080000336002017-05-01 09:29:24.575 interviewDemo[15094:2757902] person:0x6080000335e02017-05-01 09:29:24.575 interviewDemo[15094:2757902] ***********2017-05-01 09:29:24.576 interviewDemo[15094:2757902] array2 0x6080000339202017-05-01 09:29:24.576 interviewDemo[15094:2757902] person:0x6080000336002017-05-01 09:29:24.576 interviewDemo[15094:2757902] person:0x6080000335e02017-05-01 09:29:24.576 interviewDemo[15094:2757902] ***********
发现array1,array2指向同样的内存地址,array1,array2内的元素也指向同样的内存地址。array1的retainCount操作显示的是内部元素的retainCount都为2,可见内部元素进行了strong/retain操作。
3,Person不支持NSMutableCopying
@interface Person : NSObject@property (nonatomic,copy)NSString *name;@property (nonatomic,assign)NSInteger age;@property (nonatomic,copy)Person *child;@end
Person *jack = [Person new]; jack.name = @"jack"; jack.age = 1; Person *lucy = [Person new]; lucy.name = @"lucy"; lucy.age = 2; NSArray *array1 = @[jack,lucy]; NSArray *array2 = [array1 mutableCopy]; NSLog(@"array1 retainCount %@",[array1 valueForKey:@"retainCount"]); NSLog(@"array1 %p",array1); for (int i =0; i<array1.count; i++) { Person *person = array1[i]; NSLog(@"person:%p",person); } NSLog(@"***********"); NSLog(@"array2 %p",array2); for (int i =0; i<array2.count; i++) { Person *person = array2[i]; NSLog(@"person:%p",person); } NSLog(@"***********");
运行结果:
2017-05-01 10:07:37.822 interviewDemo[15227:2771155] array1 retainCount ( 3, 3)2017-05-01 10:07:37.823 interviewDemo[15227:2771155] array1 0x6000002224002017-05-01 10:07:37.823 interviewDemo[15227:2771155] person:0x6000002221602017-05-01 10:07:37.823 interviewDemo[15227:2771155] person:0x6000002223602017-05-01 10:07:37.823 interviewDemo[15227:2771155] ***********2017-05-01 10:07:37.823 interviewDemo[15227:2771155] array2 0x6000002451c02017-05-01 10:07:37.823 interviewDemo[15227:2771155] person:0x6000002221602017-05-01 10:07:37.823 interviewDemo[15227:2771155] person:0x6000002223602017-05-01 10:07:37.824 interviewDemo[15227:2771155] ***********
发现array1,array2指向不同的内存地址,array1,array2内的元素却指向同样的内存地址。array1的retainCount操作显示的是内部元素的retainCount都为3,可见内部元素进行了strong/retain操作。
4,Person支持NSMutableCopying
@interface Person : NSObject<NSMutableCopying>@property (nonatomic,copy)NSString *name;@property (nonatomic,assign)NSInteger age;@property (nonatomic,copy)Person *child;-(id)mutableCopyWithZone:(NSZone *)zone;@end@implementation Person-(id)mutableCopyWithZone:(NSZone *)zone{ Person *copy = NSCopyObject(self, 0, zone);//在非ARC下使用 copy->_name = [_name mutableCopy]; copy->_age = _age; return copy;}@end
Person *jack = [Person new]; jack.name = @"jack"; jack.age = 1; Person *lucy = [Person new]; lucy.name = @"lucy"; lucy.age = 2; NSArray *array1 = @[jack,lucy]; NSArray *array2 = [array1 mutableCopy]; NSLog(@"array1 retainCount %@",[array1 valueForKey:@"retainCount"]); NSLog(@"array1 %p",array1); for (int i =0; i<array1.count; i++) { Person *person = array1[i]; NSLog(@"person:%p",person); } NSLog(@"***********"); NSLog(@"array2 %p",array2); for (int i =0; i<array2.count; i++) { Person *person = array2[i]; NSLog(@"person:%p",person); } NSLog(@"***********");
运行结果如下:
2017-05-01 10:11:49.070 interviewDemo[15256:2774681] array1 retainCount ( 3, 3)2017-05-01 10:11:49.070 interviewDemo[15256:2774681] array1 0x60800042dc202017-05-01 10:11:49.070 interviewDemo[15256:2774681] person:0x60800022c9202017-05-01 10:11:49.070 interviewDemo[15256:2774681] person:0x6080002227402017-05-01 10:11:49.071 interviewDemo[15256:2774681] ***********2017-05-01 10:11:49.071 interviewDemo[15256:2774681] array2 0x6080000534d02017-05-01 10:11:49.071 interviewDemo[15256:2774681] person:0x60800022c9202017-05-01 10:11:49.071 interviewDemo[15256:2774681] person:0x6080002227402017-05-01 10:11:49.071 interviewDemo[15256:2774681] ***********
发现array1,array2指向不同的内存地址,array1,array2内的元素却指向同样的内存地址。array1的retainCount操作显示的是内部元素的retainCount都为3,可见内部元素进行了strong/retain操作。
如果想对容器对象的元素进行复制,容器内的元素支持NSCoding,NSMutableCopying协议。
@interface Person : NSObject<NSMutableCopying,NSCoding>@property (nonatomic,copy)NSString *name;@property (nonatomic,assign)NSInteger age;-(id)mutableCopyWithZone:(NSZone *)zone;@end@implementation Person-(id)mutableCopyWithZone:(NSZone *)zone{ Person *copy = NSAllocateObject([self class], 0, zone); copy->_name = [_name mutableCopy]; copy->_age = _age; return copy;}- (void)encodeWithCoder:(NSCoder *)aCoder{ [aCoder encodeObject:_name forKey:@"name"]; [aCoder encodeObject:@(_age) forKey:@"age"];}- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{ self = [super init]; if (self) { _name = [aDecoder decodeObjectForKey:@"name"]; _age = [[aDecoder decodeObjectForKey:@"age"] integerValue]; } return self;}@end
Person *jack = [Person new]; jack.name = @"jack"; jack.age = 1; Person *lucy = [Person new]; lucy.name = @"lucy"; lucy.age = 2; NSArray *array1 = @[jack,lucy]; NSArray* array2 = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject: array1]]; NSLog(@"array1 retainCount %@",[array1 valueForKey:@"retainCount"]); NSLog(@"array1 %p",array1); for (int i =0; i<array1.count; i++) { Person *person = array1[i]; NSLog(@"person:%p",person); } NSLog(@"***********"); NSLog(@"array2 %p",array2); for (int i =0; i<array2.count; i++) { Person *person = array2[i]; NSLog(@"person:%p",person); } NSLog(@"***********");
运行结果如下:
2017-05-01 10:36:29.352 interviewDemo[15539:2798778] array1 retainCount ( 2, 2)2017-05-01 10:36:29.353 interviewDemo[15539:2798778] array1 0x6000004247802017-05-01 10:36:29.353 interviewDemo[15539:2798778] person:0x600000424b402017-05-01 10:36:29.353 interviewDemo[15539:2798778] person:0x6000004244402017-05-01 10:36:29.353 interviewDemo[15539:2798778] ***********2017-05-01 10:36:29.353 interviewDemo[15539:2798778] array2 0x600000423f002017-05-01 10:36:29.354 interviewDemo[15539:2798778] person:0x600000424ae02017-05-01 10:36:29.354 interviewDemo[15539:2798778] person:0x6000004240a02017-05-01 10:36:29.354 interviewDemo[15539:2798778] ***********
array1,array2指向的内存地址不一样,array1,array2内的元素指向的内存地址不一样。实现了真正意义上的其内元素对象进行了复制。
- mutableCopy与copy在面试中的那些坑你知道吗?
- oc中的copy与mutableCopy
- oc中的copy与mutableCopy
- mutableCopy与COPY区别
- MutableCopy 与 Copy
- copy与mutableCopy-----笔记
- copy 与 mutablecopy
- mutableCopy与COPY区别
- ios copy 与 mutablecopy
- iOS copy与mutableCopy
- 16.copy与mutableCopy
- copy与mutableCopy
- copy与mutableCopy
- copy与mutableCopy区别
- copy 与 MutableCopy
- mutableCopy 与 copy
- NSString 的copy 与 mutableCopy
- iOS-copy与mutableCopy浅析
- matlab中创建一维数组变量的方法
- struts2+jquery+ajax实现传输List数据并解析
- java中讲讲FileInputStream的用法,举例?
- JavaScript中常用的DOM操作函数
- 【leetcode】binary-tree-postorder-traversal
- mutableCopy与copy在面试中的那些坑你知道吗?
- Bootstrap初学
- [Leetcode]_21 Merge Two Sorted Lists
- ubuntu 下配置dlib-18.16 在QT中使用
- Ubuntu下用C语言访问MySQL数据库
- 【smoj 1167】松果
- java中讲讲InputStream的用法,举例?
- 程序员的底色(IDE color scheme、CLI 命令行界面)
- JAVA源码解析-LinkedList源码