code1 使用“_”做赋值:
@interface ViewController ()
@property (nonatomic,retain) NSMutableString *rrstr;
@property (nonatomic,copy) NSMutableString *copystr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *ssss = [[NSMutableString alloc]initWithString:@"ddddd"];
_rrstr = ssss;
_copystr = ssss;
NSLog(@"%@===%@===%@",ssss,self.rrstr,self.copystr);
[ssss appendString:@"1231"];
NSLog(@"%@===%@===%@",ssss,self.rrstr,self.copystr);
[ssss deleteCharactersInRange:NSMakeRange(1, 3)];
NSLog(@"%@===%@===%@",ssss,self.rrstr,self.copystr);
}
code1 输出:
2016-09-19 10:44:29.190 retin[1160:72426] ddddd===ddddd===ddddd
2016-09-19 10:44:29.191 retin[1160:72426] ddddd1231===ddddd1231===ddddd1231
2016-09-19 10:44:29.192 retin[1160:72426] dd1231===dd1231===dd1231
code2 使用“.”做作业:
@interface ViewController ()
@property (nonatomic,retain) NSMutableString *rrstr;
@property (nonatomic,copy) NSMutableString *copystr;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableString *ssss = [[NSMutableString alloc]initWithString:@"ddddd"];
self.rrstr = ssss;
self.copystr = ssss;
NSLog(@"%@===%@===%@",ssss,self.rrstr,self.copystr);
[ssss appendString:@"1231"];
NSLog(@"%@===%@===%@",ssss,self.rrstr,self.copystr);
[ssss deleteCharactersInRange:NSMakeRange(1, 3)];
NSLog(@"%@===%@===%@",ssss,self.rrstr,self.copystr);
}
code2输出:
2016-09-19 10:50:09.079 retin[1190:75922] ddddd===ddddd===ddddd
2016-09-19 10:50:09.079 retin[1190:75922] ddddd1231===ddddd1231===ddddd
2016-09-19 10:50:09.080 retin[1190:75922] dd1231===dd1231===ddddd
我很困惑为什么这两个代码有不同的输出?这些代码不应该有相同的输出吗? “_”和“.”之间的区别究竟是什么?语法?
最佳答案
当您在 Objective-C 中声明一个 @property
时,编译器会为您做一些事情。
- 它创建一个支持实例变量来保存属性的值。默认情况下这是
_propertyName
但您可以使用@synthesize
指令覆盖它 - 它创建
getter
和setter
函数。默认情况下,这些只是设置和获取支持实例变量,但您可以再次覆盖这些函数并提供您自己的 setter 和 getter 实现。
许多人错误地认为 _propertyName
只是访问属性的“捷径”,但事实并非如此。它直接访问支持变量,绕过 setter 和 getter 函数。
在许多情况下这并不重要,但在某些情况下它确实如此,其中一种情况就是您发现的 copy
属性。
copy
是属性的属性,不是底层变量,所以声明的时候
@property (nonatomic,copy) NSMutableString *copystr;
Objective-C 创建了如下类似的 getter 和 setter 函数:
-(NSMutableString *) copyStr {
return _copyStr;
}
-(void) setCopyStr: (NSMutableString *)value {
_copyStr = [value copy];
}
所以,现在你可以看出说和说之间的区别了
_copyStr = ssss; // This is a straight pointer assignment
和
self.copyStr = ssss; // This is actually a call to [self setCopyStr:ssss]
在第一种情况下,没有调用 setter,因此永远不会获取副本; _copyStr
是对 ssss
字符串的引用,因此当您更改 ssss
时,该更改会反射(reflect)在 _copyStr
中,因为它们引用同一个对象。
在第二种情况下,调用 setter 并复制 ssss
并将对新副本的引用分配给 _copyStr
;现在,当 ssss
发生变化时,_copyStr
引用的副本不受影响。
简而言之,您应该始终使用self.propertyName
,除非您有特定原因绕过 setter/getter。
关于iOS 保留复制问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39564671/