【问题标题】:Block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behaviorBlock 隐式保留'self';明确提及“自我”以表明这是预期行为
【发布时间】:2014-03-01 21:52:14
【问题描述】:

鉴于以下情况:

- (void) someMethod
{
    dispatch_async(dispatch_get_main_queue(), ^{
        myTimer = [NSTimer scheduledTimerWithTimeInterval: 60
                                                           target: self
                                                         selector: @selector(doSomething)
                                                         userInfo: nil
                                                          repeats: NO];
    });
}

myTimer 在私有接口中声明的地方:

@interface MyClass()
{
    NSTimer * myTimer;
}
@end

如何解决以下警告:

Block 隐式保留'self';明确提及“自我”以表明这是预期行为

从我目前的发现来看,大多数建议都包括以下内容:

- (void) someMethod
{
    __typeof__(self) __weak wself = self;
    dispatch_async(dispatch_get_main_queue(), ^{
        wself.myTimer = [NSTimer scheduledTimerWithTimeInterval: 60
                                                           target: self
                                                         selector: @selector(doSomething)
                                                         userInfo: nil
                                                          repeats: NO];
    });
}

除了 myTimer 是 ivar,这意味着 wself 无权访问任何属性。

我想我的问题是:

  1. 我关心/应该关心吗?
  2. 我应该将 myTimer 声明为属性吗?

我在代码中经常使用 ivars。我刚刚在我的项目中添加了-Weverything 标志,以查看是否可以找到任何潜在问题,这是迄今为止最常见的警告。我可以通过制作我的 ivars 属性来修复它并没有问题,但我想确保在我这样做之前得到更好的理解。

【问题讨论】:

  • "除了 wself 是一个 ivar,这意味着 wself 没有访问任何属性的权限。" - 笏?
  • @H2CO3 抱歉,应该说“除了 myTimer 是 ivar”。
  • 我今天升级到 Xcode 9.3 后开始收到此警告,并遵循 Xcode 自己的建议更新项目设置。无中生有,我收到了 300 多条关于该项目的警告消息。
  • 这是 Swift 引发的警告吗?如果是这样,为什么在我们应该编写代码时仍然反对内存管理的复杂性。

标签: objective-c macos objective-c-blocks


【解决方案1】:

详情

Xcode:9.2、10.2、11.0 (11A420a)

Objective-C Pod 中的警告

我有一个快速的项目。使用 Objective-C pod 时出现警告 Block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior

  • 螺栓
  • FBSDKCoreKit
  • FBSDKLoginKit

解决方案 1(手动)

CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO

解决方案 2(自动)

添加到 Podfile 的末尾:

post_install do |installer|
      installer.pods_project.targets.each do |target|
           target.build_configurations.each do |config|
                config.build_settings['CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF'] = 'NO'
           end
      end
 end

结果

【讨论】:

  • Thx @Vasily Bodnarchuk,能够解决 Xcode 9.2 中的错误。将标志更改为否还有其他含义吗?
  • 我在三个 Swift 项目中更改了这个标志。我没有错误。
  • @user1872384 打开或关闭此标志对代码的编译方式或运行方式的影响为零。如果您隐含地引用了 self,您将不会再收到这个非常有用的警告,否则可能会引起您的注意。如果您被第三方库所困,您会收到大量这些警告,我可以理解想要关闭它。但我建议为您自己的代码保持打开此警告,并将对 self 的隐式引用替换为显式引用,并确保在这些情况下没有强引用循环。
【解决方案2】:

myTimer 替换为self->myTimer 将修复您的警告。

当您在代码中使用 iVar _iVar 时,编译器会将代码替换为 self->_iVar,如果您在块内使用它,则该块将捕获 self 而不是 iVar 本身。警告只是为了确保开发人员理解这种行为。

【讨论】:

  • 我也遇到了这个错误,但是我很困惑它会导致任何内存泄漏吗???
  • @Surbhi Garg 相反,weak 指针表示保留计数不变。唯一的问题是self 在使用之前被释放。
  • 有一点,据我所知,在方法中分配dispatch_async(而不是强烈地持有它)无论如何都不会创建保留周期。该块可能保留self,但self 不保留该块。所以我认为这些警告只是针对养成“好习惯”?
  • 最近遇到了这个警告,我想知道是否有更好的解决方案不需要我在代码中的每个 _iVar 前面加上 self->:我的块中有很多而且视觉上会很乱。
  • 你也可以将一个方法内的所有块逻辑移动到块内调用。
【解决方案3】:

对于那些因为Bolts/FBSDKCoreKit/FBSDKLoginKit 而收到这些警告的人,您应该避免使用 Vasily 的回答,而是将针对这些特定依赖项的警告静音。

选项 1

提及每个 pod 而不仅仅是 FacebookCore 并添加 inhibit_warnings: true

pod 'FacebookCore', inhibit_warnings: true
pod 'Bolts', inhibit_warnings: true
pod 'FBSDKCoreKit', inhibit_warnings: true
pod 'FBSDKLoginKit', inhibit_warnings: true

选项 2

或者通过将以下内容添加到您的 Podfile 来使所有 pod 静音:

inhibit_all_warnings!

结论

您仍会收到有关您自己的代码的警告。在某些时候没有得到这些可能会出现问题,这就是为什么我认为这是一个更好的解决方案。

下次更新 Facebook sdk 时,看看是否可以删除 inhibit_warnings: trueinhibit_all_warnings!

【讨论】:

  • 我在 Vasily 的回答中没有看到问题。它仅适用于 Pods 项目,而不适用于您的整个项目。
  • @Starsky 这是一个问题,因为它适用于所有 Pod,所以它会隐藏其他 Pod 的警告
【解决方案4】:

这解决了我的 Xcode 9.3 问题

- (void) someMethod{

    __weak MyClass *wSelf = self;

    dispatch_async(dispatch_get_main_queue(), ^{

    MyClass *sSelf = wSelf;
    if(sSelf != nil){
        wself.myTimer = [NSTimer scheduledTimerWithTimeInterval: 60
                                                       target: self
                                                     selector:@selector(doSomething)
                                                     userInfo: nil
                                                      repeats: NO];
       }

   });
}

【讨论】:

    【解决方案5】:

    最近我遇到了同样的问题,@Vasily Bodnarchuk 的回答似乎很有帮助。

    但是,在持续集成环境中,无法在运行时将 CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF 标志更改为 NO。 因此,为了隔离问题,我尝试通过检查 Cocoapods 安装的所有相关 GEMS 并发现 gem XCODEPROJ 版本 1.5.7 将 CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF 设置为 YES 每当执行 pod install 命令时。 解决方案是通过执行sudo gem install xcodeproj -v 1.5.1XCODEPROJ 恢复到早期版本 1.5.1 一旦恢复,只需执行pod install,该标志将始终设置为 NO。

    【讨论】:

    • 它对我有用!!!。答案应该被接受为正确的。它拯救了我的一天。谢谢@bhuvan
    • @PallavTrivedi - 我认为这不应该是公认的答案。不要误会我的意思,这个答案是正确的,因为它成功地消除了警告。但是这个警告非常有用。我建议让您的 self 引用明确(您可以在其中浏览代码并轻松查看强引用周期问题的候选者),而不是对 self 的不那么明显的隐式引用逃避人们的注意。 Apple 添加这个有用的警告是有原因的。
    • 我同意,我只是因为以同样的方式回答而被否决。不要通过删除它来消除警告。通过不错误地引用 self 来消除警告。它可以创建保留周期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    • 2019-11-29
    • 2016-06-01
    • 2018-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多