【问题标题】:What is a simple rule to avoid objective-c block retain cycle memory leaks?避免objective-c块保留循环内存泄漏的简单规则是什么?
【发布时间】:2014-07-04 16:31:01
【问题描述】:

我遇到过由块保留周期引起的内存泄漏。我只想要一个简单的规则,我可以将其应用于我的代码以确保我避免它们。另一方面,我不想在没有必要的情况下将我的代码库库的一半更新为__weak 指针。

这是我目前所拥有的:

使用以下内容时不会出现内存泄漏:

dispatch_async(queue, ^{...}); // GCD call.
[Foo bar:^{...}]; // Class "+" methods with completion block.

但是,这些情况肯定会导致块保留周期内存泄漏:

self.myPropertyBlock = ^{ self; };
_myInstanceVariableBlock = ^{ self; };
self.myPropertyBlock = ^{ _selfInstanceVariable; };
obj.myPropertyBlock = ^{ obj; };

这些情况可能会或可能不会导致块保留周期内存泄漏(取决于块调用对象是否保留块):

[self bar:^{ self; }];    
[self.myPropertyObj bar:^{ self; }];
[self.myPropertyObj bar:^{ _selfInstanceVariable; }];

[obj bar:^{ obj; }];
[obj.myPropertyObj bar:^{ obj; }];

为了绝对确定不会发生内存泄漏,有问题的情况需要将块内使用的selfobj 指针更改为__weak 指针,如下所示(或其他一些避免泄漏的策略):

__weak SelfClass *weakSelf = self;
self.myPropertyBlock = ^{ weakSelf; };
_myInstanceVariableBlock = ^{ weakSelf; };
self.myPropertyBlock = ^{ weakSelf.instanceVariableConvertedToProperty; };
[self bar:^{ weakSelf; }];
[self.myPropertyObj bar:^{ weakSelf; }];
[self.myPropertyObj bar:^{ weakSelf.instanceVariableConvertedToProperty; }];

__weak ObjClass *weakObj = obj
[obj bar:^{ weakObj; }];
[obj.myPropertyObj bar:^{ weakObj; }];
obj.myPropertyBlock = ^{ weakObj; };

请提醒我以上任何错误情况。

有没有更简单更好的规则?

如果你能添加一点解释来解释为什么规则有效或无效,那就太棒了。

基于答案的规则:考虑块中提到的所有对象并询问,这些对象中是否有任何对象保留此块?

【问题讨论】:

    标签: ios objective-c memory-leaks objective-c-blocks


    【解决方案1】:

    A 保留周期是 A -> B -> A(其中 -> 表示保留)。这很糟糕,因为我们无法释放保留的东西,所以释放 A 的唯一方法是释放 B,但这取决于释放 A。

    块保留循环没有什么不同,除了块更积极地保留:它们保留其中引用的任何对象,所以如果 A -> Block 和 Block 提到 A,那么 A -> Block -> A。

    所有这些都导致了编码块时的简单规则。考虑块中提到的所有对象并询问,这些对象中是否有任何保留该块?大多数时候他们没有。但是要特别注意你将块传递给的对象,换句话说:

    [beSuspiciousOfMe heresABlock:^{
        NSLog(@"does %@ retain this block?", beSuspiciousOfMe];
    }];
    

    如果您控制 beSuspiciousOfMe(可以是,而且经常是 self),这很容易检查。如果该代码由于某种原因不透明,并且您不确定,则可以使用 __weak 复制技巧。

    【讨论】:

    • “考虑块中提到的所有对象”的推论是“保持块中提到的对象的数量很小”。一个推论是“保持小块”。如何?就像函数一样。当它们变得太大时(在块的情况下,超过几行),将它们提取到函数或方法中。然后他们会更容易推理,达恩的建议也更容易实施。
    • 好的,除了将块存储在实例变量或属性中之外,还有其他方法可以让对象保留块吗?
    • 不。它就像一个对象。
    猜你喜欢
    • 1970-01-01
    • 2013-05-07
    • 2023-04-03
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多