在块中将self作为参数不会导致循环引用,但是对self的外部引用会

时间:2019-06-12 05:19:09

标签: ios objective-c automatic-ref-counting

谁能告诉我为什么当test参数和testMember变量指向同一地址时,以下代码会导致不同的结果

@interface TestClass : NSObject

@property (nonatomic, copy) void (^testBlock)(TestClass *test);

@end

@implementation TestClass

- (void)viewDidLoad {
    [super viewDidLoad];
    self.testBlock(self);
}

@end

@implementation OtherClass

- (void)viewDidLoad {
    [super viewDidLoad];

    TestClass *testMember = [[TestClass alloc] init];

    // Case 1
    testMember.testBlock = ^(TestClass *test) {
        NSLog(@"%@",test); // This does not create circular references
    };

    // Case 2
    testMember.testBlock = ^(TestClass *test) {
        NSLog(@"%@",testMember); // This creates circular references
    };
}

@end

1 个答案:

答案 0 :(得分:0)

对于情况1,test变量只是一个局部函数参数,该块没有从外部保留任何其他变量。

对于情况2,testMember对象在定义块时来自块外部,该块保留其引用计数。由于testBlock被定义为类TestClass的属性,因此testMember拥有testBlock。因此,testMembertestBlock相互保留,这就是循环引用

要解决案例2的循环保留问题,请使用以下方法:

__weak TestObject *weakMember = testMember;

testMember.testBlock = ^(TestClass *test) {
    __strong TestObject *strongMember = weakMember;
    NSLog(@"%@", strongMember);
};

因为weakMember变量不会增加实际testMember对象的引用计数,所以testBlock也不会增加。当开始执行testBlock时,strongMember尝试保留weakMember对象(该对象可能会获得nil值取决于您的逻辑设计),并在完成该块时减少引用计数。 / p>