I would expect copy on an object to generate a new object. But it seems it will only generate a different one and may reuse it for another copy.
void (^block1)(void) = ^ {
// ...
};
void (^block2)(void) = ^ {
// ...
};
typeof(block1) block3 = [block1 copy];
typeof(block1) block4 = [block1 copy];
typeof(block2) block5 = [block2 copy];
XCTAssertNotEqual(block1, block2);
XCTAssertNotEqual(block2, block3);
XCTAssertNotEqual(block3, block4); // Fail, [block1 copy] returns the same result for two requests
XCTAssertNotEqual(block4, block5);
But why does it act like this?
-copyand-copyWithZone:are described by theNSCopyingprotocol, which says the following:The object returned by
-copy/-copyWithZone:can be any object which is considered equal to the original object, while being functionally independent. Critically, this means that immutable objects are allowed to implement-copyby returningself, since they cannot be modified before or after the copy, which means that two instances with the same value would be indistinguishable (allowing them to skip making an actual copy, since it would be needless work).This is a pretty common optimization, and plenty of types implement it, including
NSString(esp. with constant strings), certain collections likeNSArrayandNSDictionary, and others:In general, you should not rely on
-copyreturning a different object from the original if the type is immutable, since it can include this optimization.(Immutable copies of mutable objects, and mutable copies in general, cannot behave this way, because mutations of either the original or the new object are not allowed to change one another; those copies are truly distinct.)
In your specific case: the blocks you declared are immutable objects, and are allowed to return
selffrom-copy, since they cannot be changed, and there's no reason to perform a full copy of the block.It's not just that
block3 == block4, but thatblock1 == block3 == block4, since-copyis returning the original block:This is not true for all types of blocks; if you're curious, this SO answer about "global" blocks, "stack" blocks, and "malloc" blocks also describes copying behavior: https://stackoverflow.com/a/29160233/169394