-copy
和-copyWithZone:
由NSCopying
协议描述,其内容如下:
"复制"的确切含义可以因类而异,但复制必须是一个功能独立的对象,其值必须与创建复制时的原始对象相同.用NSCopying
制作的副本由发送者隐含保留,发送者负责发布它.
由-copy
/-copyWithZone:
返回的对象可以是被认为与原始对象相等但在功能上独立的任何对象.关键的是,这意味着不变对象可以通过返回self
来实现-copy
,因为它们不能在复制之前或之后被修改,这意味着具有相同值的两个实例将是不可区分的(允许它们跳过制作实际副本,因为这将是不必要的工作).
这是一个非常常见的优化,很多类型都实现了它,包括NSString
(特别是.使用常量字符串)、某些集合(如NSArray
和NSDictionary
)以及其他集合:
void printEqual(id obj) {
id copy = [obj copy];
NSLog(@"%p == %p: %d", obj, copy, obj == copy);
}
printEqual(@"Hello, world!"); // => 0x1046d8048 == 0x1046d8048: 1
printEqual(@[@1, @2, @3]); // => 0x1046dc078 == 0x1046dc078: 1
printEqual(@{@"greeting": @"Hello, world!"}); // => 0x1046dc090 == 0x1046dc090: 1
通常,如果类型是不可变的,则不应该依赖于-copy
从原始对象返回different对象,因为它可以包括这种优化.
(可变对象的不可变副本以及一般的可变副本不能以这种方式运行,因为原始对象或新对象的Mutations 不允许彼此更改;这些副本是真正不同的.)
在您的特定情况下:您声明的块是不可变的对象,并且允许从-copy
返回self
,因为它们不能被更改,并且没有理由执行块的完整复制.
不仅仅是那block3 == block4
,还有那block1 == block3 == block4
,因为-copy
返回的是原始块:
NSLog(@"%p == %p: %d", block1, block3, block1 == block3); // => 0x600001dc0b70 == 0x600001dc0b70: 1
NSLog(@"%p == %p: %d", block1, block4, block1 == block4); // => 0x600001dc0b70 == 0x600001dc0b70: 1
这并不适用于all种类型的块;如果您很好奇,下面的关于"全局"块、"堆栈"块和"Malloc"块的答案也描述了复制行为:https://stackoverflow.com/a/29160233/169394