copy和mutableCopy

来源:互联网 发布:淘宝客qq群推广违规吗 编辑:程序博客网 时间:2024/05/09 11:37

一、copy和mutableCopy

NSObject类有两个跟拷贝相关的方法:copy和mutableCopy。这两个方法都是返回一个id类型的对象。

  • ①、copy方法:返回copyWithZone方法返回的对象(Returns the object returned by copyWithZone:);
  • ②、mutableCopy方法:返回mutableCopyWithZone方法返回的对象(Returns the object returned by mutableCopyWithZone:);

二、NSString对象调用copy和mutableCopy

  • 1、先定义如下通用宏:
//打印方法名#define LOG_METHOD_NAME {NSLog(@"%@", NSStringFromSelector(_cmd));}//打印对象的类名,以及对象本身的地址#define LOG_OBJ_ADDRESS(obj) {NSLog(@"%@ : %p",NSStringFromClass([obj class]), obj);}//打印空行#define LOG_END {NSLog(@"%@", @" ");}
  • 2、测试代码如下:
- (void)stringCopyTest{    LOG_METHOD_NAME    NSString *str = @"Hello";    LOG_OBJ_ADDRESS(str);    NSString *cpStr = [str copy];    LOG_OBJ_ADDRESS(cpStr);    NSMutableString *mutCpStr = [str mutableCopy];    LOG_OBJ_ADDRESS(mutCpStr);    LOG_END}
  • 3、打印如下:

    2015-12-22 15:14:33.416 toast显示[53390:2099784] stringCopyTest2015-12-22 15:14:33.416 toast显示[53390:2099784] __NSCFConstantString : 0x10aed26b02015-12-22 15:14:33.416 toast显示[53390:2099784] __NSCFConstantString : 0x10aed26b02015-12-22 15:14:33.416 toast显示[53390:2099784] __NSCFString : 0x7fe071c1ee402015-12-22 15:14:33.416 toast显示[53390:2099784]
  • 4、总结
    由以上输出可知,对一个NSString对象调用copy返回的还是该对象本身,因为str的地址和cpStr的地址是用一个。而调用mutableCopy,返回的是一个NSMutableString对象。

    注:__NSCFConstantString是常量串即NSString,而__NSCFString是可变串即NSMutableString

二、NSMutableString对象调用copy和mutableCopy

  • 1、测试代码如下:
- (void)mutableStringCopyTest{    LOG_METHOD_NAME    NSMutableString *mutStr = [@"OC" mutableCopy];    LOG_OBJ_ADDRESS(mutStr);    NSMutableString *cpMutStr = [mutStr copy];    LOG_OBJ_ADDRESS(cpMutStr);    NSMutableString *mutCpMutStr = [mutStr mutableCopy];    LOG_OBJ_ADDRESS(mutCpMutStr);    LOG_END}
  • 2、打印如下:

    2015-12-22 15:20:06.162 toast显示[53437:2103898] mutableStringCopyTest2015-12-22 15:20:06.163 toast显示[53437:2103898] __NSCFString : 0x7fe4b1d133f02015-12-22 15:20:06.163 toast显示[53437:2103898] NSTaggedPointerString : 0xa0000000000434f22015-12-22 15:20:06.163 toast显示[53437:2103898] __NSCFString : 0x7fe4b1c033a02015-12-22 15:20:06.163 toast显示[53437:2103898]
  • 3、总结
    由以上输出可知,对一个NSMutableString对象调用copy返回的是一个NSTaggedPointerString对象,该对象可认为是一个常量串。而调用mutableCopy返回的是另外一个可变对象__NSCFString,即NSMutableString(原NSMutableString对象的地址是0x7fe4b1d133f0,新NSMutableString的对象地址是0x7fe4b1c033a0)。

    PS:针对NSArray、NSDictionary、NSSet等具有Mutable版本的类进行实验出现跟NSString类似的现象;

三、copy和mutableCopy调用小结

  • 针对不可变对象调用copy返回该对象本身,调用mutableCopy返回一个可变对象(新的);

  • 针对可变对象调用copy返回一个不可变对象(新的),调用mutableCopy返回另外一个可变对象(新的)。

class copy mutableCopy 不可变(如,NSString) 返回本身(相当于retain一次) 创建新的可变对象(如,创建一个NSMutableString对象,自制跟远对象不同) 可变(如,NSMutableString) 创建新的不可变对象(如,创建一个NSTaggedPointerString对象,地址跟原对象不同) 创建新的可变对象(如,创建一个NSMutableString对象,地址跟远对象不同)

四、属性copy还是strong

  • 1、假设定义两个id类型如下
@property (nonatomic, copy) id cpID;@property (nonatomic, strong) id stID;
  • 2、那么编译器把以上两属性分别实现为:
@synthesize cpID = _cpID;@synthesize stID = _stID;- (void)setCpID:(id)cpID{    _cpID = [cpID copy];}- (id)cpID{    return _cpID;}- (void)setStID:(id)stID{    _stID = stID;}- (id)stID{    return _stID;}

3、结论:
从以上实现可以看出,strong和copy的属性主要是set方法有区别,strong的set是直接设置指定值,而copy的set是设置指定值的copy版本。

五、NSString的属性是copy还是strong

  • 1、测试代码如下:
@interface ViewController ()@property (nonatomic, copy) NSString *cpStr;@property (nonatomic, strong) NSString *stStr;@end@implementation ViewController- (void)stringPropertyTest{    LOG_METHOD_NAME;    NSMutableString* mutStr = [@"123" mutableCopy];    LOG_OBJ_ADDRESS(mutStr);    self.cpStr = mutStr;    LOG_OBJ_ADDRESS(self.cpStr);    self.stStr = mutStr;    LOG_OBJ_ADDRESS(self.stStr);    NSLog(@"修改前");    NSLog(@"mutStr:%@", mutStr);    NSLog(@"copy:%@", self.cpStr);    NSLog(@"strong:%@", self.stStr);    [mutStr appendString:@"456"];    NSLog(@"修改后");    NSLog(@"mutStr:%@", mutStr);    NSLog(@"copy:%@", self.cpStr);    NSLog(@"strong:%@", self.stStr);    LOG_END}
  • 2、打印结果如下:

    2015-12-29 00:13:13.630 toast显示[10615:514242] stringPropertyTest2015-12-29 00:13:13.630 toast显示[10615:514242] __NSCFString : 0x7fd63851f6a02015-12-29 00:13:13.630 toast显示[10615:514242] NSTaggedPointerString : 0xa0000000033323132015-12-29 00:13:13.630 toast显示[10615:514242] __NSCFString : 0x7fd63851f6a02015-12-29 00:13:13.630 toast显示[10615:514242] 修改前2015-12-29 00:13:13.630 toast显示[10615:514242] mutStr:1232015-12-29 00:13:13.630 toast显示[10615:514242] copy:1232015-12-29 00:13:13.631 toast显示[10615:514242] strong:1232015-12-29 00:13:13.631 toast显示[10615:514242] 修改后2015-12-29 00:13:13.631 toast显示[10615:514242] mutStr:1234562015-12-29 00:13:13.631 toast显示[10615:514242] copy:1232015-12-29 00:13:13.632 toast显示[10615:514242] strong:1234562015-12-29 00:13:13.632 toast显示[10615:514242]
  • 3、结论:
    由以上输出可知,假设两个NSString属性实际上指向的都是一个NSMutableString对象,那么在原NSMutableString对象修改后,strong版本的NSString属相跟着修改,而copy版本属性保持原状。self.cpStr实际上是一个NSTaggedPointerString对象,该对象正是NSMutableString对象执行copy的返回值;

六、NSMutableString的属性是copy还是strong

  • 1、测试代码如下:
@interface ViewController ()@property (nonatomic, copy) NSMutableString *cpMutStr;@property (nonatomic, strong) NSMutableString *stMutStr;@end@implementation ViewController- (void)stringPropertyTest{    LOG_METHOD_NAME;    NSMutableString* mutStr = [@"123" mutableCopy];    LOG_OBJ_ADDRESS(mutStr);    self.cpMutStr = mutStr;    LOG_OBJ_ADDRESS(self.cpMutStr);    self.stMutStr = mutStr;    LOG_OBJ_ADDRESS(self.stMutStr);    NSLog(@"修改前");    NSLog(@"mutStr:%@", mutStr);    NSLog(@"copy:%@", self.cpMutStr);    NSLog(@"strong:%@", self.stMutStr);    [mutStr appendString:@"456"];    NSLog(@"修改后");    NSLog(@"mutStr:%@", mutStr);    NSLog(@"copy:%@", self.cpMutStr);    NSLog(@"strong:%@", self.stMutStr);    LOG_END    [self.cpMutStr appendString:@"789"];}
  • 2、打印结果如下:

    2015-12-29 00:31:24.807 toast显示[570:9278] stringPropertyTest2015-12-29 00:31:24.807 toast显示[570:9278] __NSCFString : 0x7fec70c20c602015-12-29 00:31:24.807 toast显示[570:9278] __NSCFString : 0x7fec70c3e9502015-12-29 00:31:24.807 toast显示[570:9278] __NSCFString : 0x7fec70c20c602015-12-29 00:31:24.807 toast显示[570:9278] 修改前2015-12-29 00:31:24.807 toast显示[570:9278] mutStr:1232015-12-29 00:31:24.808 toast显示[570:9278] copy:1232015-12-29 00:31:24.808 toast显示[570:9278] strong:1232015-12-29 00:31:24.808 toast显示[570:9278] 修改后2015-12-29 00:31:24.808 toast显示[570:9278] mutStr:1234562015-12-29 00:31:24.808 toast显示[570:9278] copy:1232015-12-29 00:31:24.808 toast显示[570:9278] strong:1234562015-12-29 00:31:24.808 toast显示[570:9278]
  • 3、结论:
    看起来没啥问题,strong版本的属性跟随原对象的变化而变化,copy版本的属性不变。但是,假设调用

    [self.cpMutStr appendString:@"789"];

    程序会崩溃。崩溃信息如下:

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString appendString:]: unrecognized selector sent to instance 0xa000000003332313'*** First throw call stack:

    原因很明显,是朝NSTaggedPointerString对象发了一个它不能识别的selector。原因是copy版本的NSMutableString属性本质上不是一个NSMutableString对象,而是一个NSTaggedPointerString对象,它是一个不可变对象。该对象是NSMutableString对象执行copy得来的,还记得我们上一节的结论吗?对一个对象执行copy得到的用于是一个不可变的对象。

    PS:针对NSArray、NSDictionary、NSSet等具有Mutable版本的类进行试验出现跟NSString类似的现象。

本文来至从copy和mutableCopy谈起

0 0