【问题标题】:Reference to self inside block块内引用自身
【发布时间】:2012-10-15 18:13:00
【问题描述】:

现在我有一段这样的代码:

__strong MyRequest *this = self;

 MyHTTPRequestOperation *operation = [[MyHTTPRequestOperation alloc]initWithRequest:urlRequest];
 [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *request, id responseObject) {
     [this requestFinished:request];
 }
 failure:^(AFHTTPRequestOperation *request, NSError *error) {
     [this requestFailed:request withError:error];
 }];

我这样做主要是因为其他一些类继承自这段代码所在的类,并实现了自己的 requestFinished 和 requestFailed。

如果我将自引用更改为 __weak,我开始收到一些 EXC_BAD_ACCESS 错误。使用 __strong 引用一切正常,但我担心创建保留周期。 请注意,我使用的是 ARC。

此代码是否会创建会导致问题的保留周期?有什么简单的解决方案吗?我可以遵循哪些不同的方法来让继承类实现自己的方法来处理响应?

【问题讨论】:

  • 崩溃在哪里?完成/失败的方法包含什么?正如所写,确切的代码不会因 __weak 崩溃。
  • 我不明白this 变量的必要性。为什么不使用该变量就不能直接调用[self requestFinished]?如果您有MyRequest 类的子类并覆盖requestFinished,那么无论如何都会调用该子类的自定义requestFinished
  • @jere:你不应该在一个块中强烈引用self(参见this question)。
  • @Tim:这根本不是真的。只要self 没有对该块的强引用就可以了
  • newacct:非常好的观点,我之前的评论(在这方面)颇具误导性。 @jere:在块内强烈引用self 的危险是您可能会创建一个保留循环,以后不能将其作为垃圾收集;正如newacct 指出的那样,当self 也对该块具有强引用时,就会发生这种情况。由于两者相互引用,因此它们都有效地防止了彼此被释放。 (我认为我链接的问题解释了这一点,但我之前的总结很不清楚 - 抱歉!)

标签: iphone objective-c ios objective-c-blocks


【解决方案1】:

是的,它创建了一个保留周期。它会引起问题吗?也许吧。

如果 API 支持,您可以重置处理程序,这将手动中断保留周期:

[operation setCompletionBlockWithSuccess:nil failure:nil];

或者您可以使用弱引用。但是,您说您尝试了弱引用,但它崩溃了。弱引用保证在消息开始时为 nil,或者在消息被处理之前保持有效。换句话说,考虑...

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    [weakSelf doSomething];
});

如果异步块执行时weakSelf 为 nil,则“什么都没有”发生。如果它不是 nil,那么它保证至少在 doSomething 完成之前被保留。实际上,它类似于:

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    { id obj = weakSelf; [weakSelf doSomething]; obj = nil; }
});

但请注意,如果您这样做:

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    [weakSelf doSomething];
    [weakSelf doSomethingElse];
});

对象可能在doSomethingdoSomethingElse 之间变为nil。

此外,如果您通过弱引用访问实例变量,您只是在请求 SEGV:

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    foo = weakSelf->someIVar; // This can go BOOM!
});

因此,如果您的处理程序正在访问单个消息的弱引用,那么您应该没问题。其他任何事情都应该做“弱-强-舞”。

__weak MyRequest *weakSelf = self;
dispatch_async(someQ, ^{
    MyRequest *strongSelf = weakSelf;
    if (!strongSelf) return;
    [strongSelf doSomething];
    [strongSelf doSomethingElse];
    foo = strongSelf->someIVar;
});

如果您认为自己遵循了指导方针,那么也许一个更完整的源代码示例以及崩溃详细信息会有所帮助...

【讨论】:

  • 周期在哪里?该块保留selfoperation 保留该块。但我没有看到self 在任何地方保留operation
  • @newacct 对。循环在原始代码中并不明确,但问题只包含一个 sn-p - 我通常只是忽略这样的问题,因为它们缺乏信息,而且大多数时候我只能做出假设 - 这几乎总是一个坏主意.也许我也应该忽略这个。无论如何,由于它在弱时失败,但在强时有效,我假设操作由自身强烈持有 - 这会产生循环。我的帖子是展示如何打破一个,假设它在那里......不证明在这种情况下存在一个。
  • 感谢您的完整解释,将来我会尝试提供更多有关问题周围环境的信息。我很快就会针对我的具体问题添加一些额外的 cmets。
  • 使用 dispatch_async 作为示例具有误导性,因为 self 没有强烈引用它,因此不存在保留周期的威胁。还是我理解不正确?
  • @Remover Peace。我只是想展示如何使用弱来打破保留周期,并将其用作显示异步调用的一种方式。保留周期有很多不同的风格,我可能应该使用一个更好的例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-13
  • 1970-01-01
  • 2013-10-01
  • 2011-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多