其他分享
首页 > 其他分享> > iOS 属性什么时候用copy,什么时候用strong?

iOS 属性什么时候用copy,什么时候用strong?

作者:互联网

先说总结:

1.对于不可变属性,推荐使用copy,能防止不可变对象变成可变对象,从而防止值发生不可控变化。
2.对于可变属性,推荐使用strong,因为用copy修饰后,会变成不可变对象,再调用可变对象的函数时会crash。

1、当修饰的属性为"不可变"时:如NSString、NSArray、NSDictionary:

首先,用copy和strong声明两个不可变属性

@property (nonatomic, strong) NSString *strongStr;
@property (nonatomic, copy  ) NSString *copyedStr;

1.1 初始化一个"不可变"对象,并将其赋值给strongStr和copyedStr:

	NSString *str = @"123";
    _strongStr = str;
    _copyedStr = str;
    NSLog(@"%p, %p, %p    %@, %@, %@", str, _strongStr, _copyedStr, str, _strongStr, _copyedStr);

输出结果:

2021-09-15 20:37:38.980779+0800 test[96724:6373515] 0x10653d068, 0x10653d068, 0x10653d068    123, 123, 123

【可以看出:对于"不可变"对象,copy和strong指向的都是str的内存地址,copy对于不可变对象进行的是浅拷贝。】

此时,对str进行修改:

	str = @"456";
    NSLog(@"%p, %p, %p    %@, %@, %@", str, _strongStr, _copyedStr, str, _strongStr, _copyedStr);

输出结果:

2021-09-15 20:37:38.981080+0800 test[96724:6373515] 0x10653d0a8, 0x10653d068, 0x10653d068    456, 123, 123

【可以看出:copy、strong指向的内存地址和内存地址中的值都没变,str重新开辟内存地址进行了修改。因为他们原本指向的内存地址的值是不可变的,str想要修改就得自立山头。】

1.2 初始化一个"可变"对象,并将其赋值给strongStr和copyedStr:

	NSMutableString *mulStr = [[NSMutableString alloc] initWithString:@"PPP"];
    _strongStr = mulStr;
    _copyedStr = mulStr;
    NSLog(@"%p, %p, %p    %@, %@, %@", mulStr, _strongStr, _copyedStr, mulStr, _strongStr, _copyedStr);

输出结果:

2021-09-15 20:49:46.263158+0800 test[97029:6382020] 0x600000001fb0, 0x600000001fb0, 0x600000001fb0    PPP, PPP, PPP

【可以看出:copy和strong都指向str的内存地址,而且内存地址的值是个NSMutableString可变类型】

此时,对mulStr的值进行修改:

	[mulStr appendString:@"++"];
    NSLog(@"%p, %p, %p    %@, %@, %@", mulStr, _strongStr, _copyedStr, mulStr, _strongStr, _copyedStr);

输出结果:

2021-09-15 20:49:46.263429+0800 test[97029:6382020] 0x600000001fb0, 0x600000001fb0, 0x600000001fb0    PPP++, PPP++, PPP++

【可以看出:①mulStr是在原本内存地址进行值得修改;②修改任意一个对象的值,三者的值都跟着改变;原因:因为mulStr、_strongStr和_copyedStr指向的内存地址的值是个NSMutableString可变类型,是允许修改的,所以当mulStr发生变化时直接修改了原本内存地址的值,指向这块内存地址的_strongStr和_copyedStr自然也跟着变化。(这正是潜在的危险之处,所以推荐对于不可变属性用copy修饰)】

// =========== 分隔符 ============

2、当修饰的属性为“可变”时:如NSMutableString、NSMutableArray、NSMutableDictionary:

首先,用copy和strong声明两个可变属性:

@property (nonatomic, strong) NSMutableString *strongMulStr;
@property (nonatomic, copy  ) NSMutableString *copyedMulStr;

2.1 初始化一个"可变"对象,并将其赋值给strongMulStr和copyedMulStr:

	NSMutableString *mulStr = [[NSMutableString alloc] initWithString:@"abc"];
	self.strongMulStr = mulStr;
	self.copyedMulStr = mulStr;
	NSLog(@"%p, %p, %p    %@, %@, %@", mulStr, _strongMulStr, _copyedMulStr, mulStr, _strongMulStr, _copyedMulStr);

输出结果:

2021-09-15 21:17:03.368775+0800 test[97765:6402607] 0x6000003860d0, 0x6000003860d0, 0xcf1bace00b0cb946    abc, abc, abc

【可以看出:mulStr和strong对象指向同一块内存地址,而copy修饰的可变对象此时进行了深拷贝重新申请了一块内存地址】

此时,修改mulStr的值:

	[mulStr appendFormat:@"def"];
    NSLog(@"%p, %p, %p    %@, %@, %@", mulStr, _strongMulStr, _copyedMulStr, mulStr, _strongMulStr, _copyedMulStr);

输出结果:

2021-09-15 21:17:03.369691+0800 test[97765:6402607] 0x6000003860d0, 0x6000003860d0, 0xcf1bace00b0cb946    abcdef, abcdef, abc

【可以看出:由于mulStr内存地址的值是NSMutableString可变类型,所以直接在原本内存地址进行修改,导致指向这块内存地址的_strongMulStr也跟着改变,而_copyedMulStr是另一块内存所以不受影响。】

2.2 初始化一个"不可变"对象,并将其赋值给strongMulStr和copyedMulStr:

	NSString *str = @"PPP";
    self.strongMulStr = str;
    self.copyedMulStr = str;
    NSLog(@"%p, %p, %p    %@, %@, %@", str, _strongMulStr, _copyedMulStr, str, _strongMulStr, _copyedMulStr);

输出结果:

2021-09-15 21:21:06.253837+0800 test[97867:6405460] 0x10fea6068, 0x10fea6068, 0x10fea6068    PPP, PPP, PPP

【可以看出:_strongMulStr和_copyedMulStr都指向了str的内存地址,并且内存地址的值是个NSString不可变类型】

此时,修改str的值:

	str = @"PPP++";
    NSLog(@"%p, %p, %p    %@, %@, %@", str, _strongMulStr, _copyedMulStr, str, _strongMulStr, _copyedMulStr);

输出结果:

2021-09-15 21:21:06.254076+0800 test[97867:6405460] 0x10fea60a8, 0x10fea6068, 0x10fea6068    PPP++, PPP, PPP

【可以看出:①str的内存地址重新申请了,因为原本的内存地址的值是NSString不可变类型,想要重新赋值就要申请新的内存;②_strongMulStr和_copyedMulStr的值没有变,因为str重新申请了一块内存进行赋值,对他们没有影响。】

再看个东西,如果对_strongMulStr和_copyedMulStr进行修改:(会crash

    NSString *str = @"PPP";
    self.strongMulStr = str; //指向了str这个不可变内存地址
    self.copyedMulStr = str; //指向了str这个不可变内存地址
    [self.strongMulStr appendString:@"~~"];//crash
    [self.copyedMulStr appendString:@"~~"];//crash

输出结果:
直接crash。为什么修改NSMutableString这个可变对象会crash呢?

原因不同:
对于strongMulStr,虽然定义的是NSMutableString属性,但是由于赋值时指向了str这个不可变对象而变成了NSString,而NSString里没有appendString:这个函数,所以报错;
对于copyedMulStr,虽然定义的是NSMutableString属性,但是用copy修饰后进行了深拷贝,变成了NSString类型,也不能再调用appendString:函数。

总结:
1.对于不可变属性,推荐使用copy,能防止不可变对象变成可变对象,从而防止值发生不可控变化。
2.对于可变属性,推荐使用strong,因为用copy修饰后,会变成不可变对象,再调用可变对象的函数时会crash。

标签:strongMulStr,copy,str,iOS,copyedMulStr,strong,内存地址,mulStr
来源: https://blog.csdn.net/a17737812427/article/details/120316465