块中引用的实例变量和临时变量有什么区别?

What's the difference between instance variable and temporary variable referenced in block?

demo screenshot

如截图所示。

//
//  ViewController.m
//  Test
//
//  Created by jam on 15/11/4.
//  Copyright © 2015年 Baidu Inc. All rights reserved.
//

#import "ViewController.h"
#import "CJTestObject.h"

@interface ViewController ()

@property (strong, nonatomic) CJTestObject *testObject1;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    _testObject1 = [[CJTestObject alloc] init];
    CJTestObject *testObject2 = [[CJTestObject alloc] init];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"_testObject1: %@", _testObject1);
        NSLog(@"testObject2: %@", testObject2);
    });
    _testObject1 = nil;
    testObject2 = nil;
}
@end

控制台输出

2015-11-20 18:07:28.855 Test[33585:417965] _testObject1: (null)
2015-11-20 18:07:28.857 Test[33585:417965] testObject2: <CJTestObject: 0x79f564f0>

我的问题是块中引用的这两种变量有什么不同

在你的例子中,你有这 2 个对象类型的变量,所以你的块应该在你的例子中保留它们。

但这里的主要区别在于 testObject2(在方法范围内声明的变量)将被保留,但是当您在块中捕获 _testObject1 时,它会保留 self 而不是一个 _testObject1 (在你的例子中)。 在块中捕获实例变量会导致保留 self,因此当此块存在时,块将保留对 self 的强引用。

复制块时,它们引用的任何局部对象变量都会自动保留。当块被销毁时,它们会自动释放。这有助于确保引用保持有效。任何对 self 的引用都是对局部对象变量的引用,导致 self 被保留。对实例变量的任何引用都是对 self 的隐式引用并导致相同的事情。

您可以在这篇精彩的博客中找到更多详细信息

https://mikeash.com/pyblog/friday-qa-2009-08-14-practical-blocks.html

更新: 至于你的控制台输出,当块被执行时发生了什么:

NSLog(@"testObject1: %@", _testObject1);

这里它复制了对 self 的引用,并在执行时取消引用它的 _testObject1 实例变量 "pointer"。在 C 中它看起来像 self->_testObject1。 您将对 _testObject1 的引用设置为 nil,2 秒后您的块将查看此 'updated' 引用。

NSLog(@"testObject2: %@", testObject2);

此处复制了您的块并保留了对 testObject2 的引用。当您设置 testObject2 = nil 时,您将变量的引用设置为 nil。但是块仍然有 'copied' 并保留变量的地址,因此它存储并打印该值。

看起来有点复杂,但我希望能理解我的回答:)