你看不到 setter 的 Obj-C 代码,只有汇编器。为此,首先在 Xcode 中选择包含该属性的源文件,然后选择菜单项 Produce > Perform Action > Assemble "File.m"。这将打开一个包含汇编代码的窗口。搜索 setPropertyName:,其中 PropertyName 是您的资产的大写名称。
这将显示 setter 调用 _objc_setProperty_nonatomic_copy 或 _objc_setProperty_atomic_copy。要查看这些代码,您需要使用调试器并单步执行。他们基本上只是打电话给copyWithZone:。
更重要的是面试问题背后的原因。无论是简单的实验,还是通过上面的汇编程序进行挖掘,都表明copy 属性属性始终执行copy 而不是mutableCopy。所以声明:
@property (nonatomic, copy) NSMutableArray *shouldBeInvalid;
在理想情况下会产生编译器错误。如果为属性分配一个可变数组值:
self.shouldBeInvalid = @[ @24 ].mutableCopy;
那么由于copy,实际分配的值是一个不可变数组(NSArray),与NSMutableArray声明的类型相矛盾。稍后尝试将属性值用作可变数组:
[self.shouldBeInvalid addObject:@42];
将产生运行时错误,因为属性的值是与其声明类型相反的不可变对象...
您还会发现编译器很高兴地允许您将不可变数组分配给属性:
self.shouldBeInvalid = @[ @24 ];
没有任何警告。
面试官可能想要你解释的是,对于属性copy + 可变类型在 Objective-C 中没有意义,因为副本会产生不可变的对象值。但是,具有copy 和不可变对象类型(NSArray、NSDictionary 等)的属性确实有意义,因此如果为可变对象值分配了它的不可变副本,则会生成它的不可变副本,从而防止属性值发生变化出乎意料,例如:
@property (nonatomic) NSArray *shouldHaveCopy;
NSMutableArray *sample = @[ @"oops" ].mutableCopy;
self.shouldHaveCopy = sample;
[sample addObject:@"'immutable' property changed"];
// self.shouldHaveCopy now references a two element array despite
// its type being `NSArray`
所以一般规则是:
- 旨在具有可变对象值的属性 (
NSMutableDictionary et al) 永远不应指定 copy;和
- 当存在对应的可变对象子类时(例如,
NSArray 具有 NSMutableArray 等),旨在具有不可变对象值的属性应始终指定 copy。
HTH