捕获的 __weak 变量是否会被 _block_copy() 函数复制到堆中?

Will a captured __weak variable be copied to heap with the _block_copy() function?

当捕获一个__strong变量的Block被复制到堆中时,该变量也被_block_copy()函数复制到堆中。

但是使用 __weak 变量会发生什么?

id __weak weakObj = someObj;
someBlock = [^() {
   //using __weak variable
} copy];

我试过这个:

NSNumber *testNumber = [[NSNumber alloc] initWithInt:5];

NSNumber *__weak weakObj = testNumber;
NSLog(@"original weakObj address = %p",&weakObj);

id someBlock = [^() {
    NSLog(@"value in block:%ld",(long)weakObj.integerValue);
    NSLog(@"weakObj address inside block = %p",&weakObj);
} copy];

testNumber = [[NSNumber alloc] initWithInt:6];
NSLog(@"value outside:%ld",(long)testNumber.integerValue);

[someBlock invoke];

NSLog(@"weakObj address = %p",&weakObj);

结果是:

original weakObj address = 0x7fff5fbff750
value outside:6
value in block:5
weakObj address inside block = 0x1005023f0
weakObj address = 0x7fff5fbff750

结论:

  1. 在块内部,弱对象的内存地址被改变了。因此,弱对象被复制到堆中。并且可以使用 __block_copy() 函数。

  2. 块外,弱对象复制后保持原来的内存地址

当一个块捕获任何非__block变量时,该变量总是被复制到与块一起保存的独立副本中当块被创建时,而不是当块被复制。即使块 没有 移动到堆也是如此。无论变量的类型如何(无论是原始类型,还是 ARC 管理的强指针或弱指针类型)也是如此。

例如,如果您 运行 以下示例关闭了 ARC:

int foo = 5;
void (^someBlock)(void) = ^{
  NSLog(@"value in block: %d", foo);
};
foo = 6;
NSLog(@"value outside block: %d", foo); // logs "value outside block: 6"
someBlock();                            // logs "value in block: 5"
NSLog(@"block is: %@", someBlock);      // logs "block is: <__NSStackBlock__: 0x7fff523f0ba0>"

您会注意到该块从未移动到堆中,因为它在末尾是一个 __NSStackBlock__(我在关闭 ARC 的情况下执行此操作以控制块的复制,因为 ARC 可能隐含地防御性地将块移动到堆上)。您还会注意到,块内变量的值不受块创建后块外变量赋值的影响,证明变量在赋值之前(即块创建时)被复制。这个演示是用原语 int 完成的,以表明它适用于任何类型——它不仅适用于 ARC 管理的指针类型——而且对于 ARC 管理的指针类型仍然同样适用,两者有强有弱。