iOS10 __weak指针使retainCount +1

时间:2017-12-05 14:33:06

标签: objective-c retaincount

当我使用 __ weak 指针引用NSObject时,会显示意外的retainCount。

测试代码和结果如下图所示。 Result

以下是代码:

    id obj1 = [[NSObject alloc] init];
    id __weak obj2 = obj1;
    NSLog(@"obj1: %ld", CFGetRetainCount((__bridge CFTypeRef)obj1));        // line 31
    NSLog(@"obj2: %ld", CFGetRetainCount((__bridge CFTypeRef)obj2));        // line 32
    NSLog(@"obj1 again: %ld", CFGetRetainCount((__bridge CFTypeRef)obj1));  // line 33

所以〜我的困惑是,obj2的retainCount预计为1,为什么retainCount为2?

我已经从书中读到:__ weak指针将对象注册到 autoreleasepool ,因此保留计数为+。

然而,obj1和obj2指的是相同的内存地址,在这种情况下,obj1的retainCount也应该变为2.但是,它仍然保留在1中。

我知道retainCount是不可靠的,但我很好奇这是怎么来的。 (我的环境是Xcode 8.3.3,iOS 10.3)

非常感谢任何人都可以向初学者解释这一点:)

1 个答案:

答案 0 :(得分:6)

保留计数的确切值通常是一个实现细节,它依赖于编译器,Objective-C语言运行库以及所涉及的任何其他库(如Foundation)。但是,只要你不依赖于这种行为,就可以理解它为什么会这样做。

你的书是错的,或者你误解了它。使用__weak并不会将对象放入autoreleasepool。

以下是第32行(具有@"obj2: %ld"格式字符串的那个)的情况。

为了安全地将对象引用传递给函数或方法(如NSLog),它必须是一个强引用的引用。因此,编译器会在obj2上生成对objc_loadWeakRetained的调用。此函数以原子方式递增对象的保留计数并返回引用。因此,在将对象引用传递给NSLog之前,对象的保留计数从1到2。

然后,在NSLog返回后,编译器生成对objc_release的调用。因此,保留计数从第3个NSLog开始从2减少到1。

如果您想确定发生了什么,请查看编译器的汇编输出。您可以让Xcode向您展示:

assembly from menu

这是大会的相关部分:

    .loc    2 0 9 discriminator 1   ## /Users/mayoff/TestProjects/test/test/main.m:0:9
    leaq    -32(%rbp), %rdi
    ##DEBUG_VALUE: obj2 <- [%RBP+-32]
    .loc    2 16 66 is_stmt 1       ## /Users/mayoff/TestProjects/test/test/main.m:16:66
    callq   _objc_loadWeakRetained
    movq    %rax, %rbx
Ltmp4:
    .loc    2 16 29 is_stmt 0       ## /Users/mayoff/TestProjects/test/test/main.m:16:29
    movq    %rbx, %rdi
    callq   _CFGetRetainCount
    movq    %rax, %rcx
Ltmp5:
Ltmp20:
## BB#3:
    ##DEBUG_VALUE: obj2 <- [%RBP+-32]
    ##DEBUG_VALUE: obj1 <- %R15
Ltmp6:
    .loc    2 16 9 discriminator 1  ## /Users/mayoff/TestProjects/test/test/main.m:16:9
    leaq    L__unnamed_cfstring_.4(%rip), %rdi
    xorl    %eax, %eax
    movq    %rcx, %rsi
    callq   _NSLog
Ltmp7:
Ltmp21:
## BB#4:
    ##DEBUG_VALUE: obj2 <- [%RBP+-32]
    ##DEBUG_VALUE: obj1 <- %R15
    .loc    2 16 9 discriminator 2  ## /Users/mayoff/TestProjects/test/test/main.m:16:9
    movq    %rbx, %rdi
    callq   *_objc_release@GOTPCREL(%rip)

第16行是(在我的测试中)使用obj2的那一行。您可以在致电objc_loadWeakRetained之前看到对CFGetRetainCount的来电,并在objc_release之后致电NSLog