Block implicitly retains 'self'; explicitl

2019-01-13 13:35发布

问题:

Given the following:

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

Where myTimer is declared in a private interface:

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

How would one fix the following warning:

Block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior

From what I have found so far, most suggestions involve putting something such as:

- (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];
    });
}

Except, that myTimer is an ivar, meaning wself does not have access to any properties.

I guess my questions are:

  1. Do/should I care?
  2. Should I declare myTimer as a property?

I use ivars quite a bit through my code. I just added the -Weverything flag to my project to see if I can find any underlying issues and this is by far the most common warning. I have no problem going though and fixing it by making my ivars properties, but I want to make sure I get a better understanding before I do that.

回答1:

Replacing myTimer by self->myTimer would fix your warning.

When you use an iVar _iVar in the code, the compiler will replace the code by self->_iVar, and if you use it inside a block, the block will capture self instead of the iVar itself. The warning is just to make sure the the developer understand this behaviour.



回答2:

Details

Xcode: 9.2

Warnings in Objective-C Pods

I have swift project. Warning Block implicitly retains 'self'; explicitly mention 'self' to indicate this is intended behavior appears when I use Objective-C pods:

  • Bolts
  • FBSDKCoreKit
  • FBSDKLoginKit

Solution 1 (manual)

CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = NO

Solution 2 (automatic)

Add to the end of your 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

Results



回答3:

For those of you getting these warnings because of Bolts/FBSDKCoreKit/FBSDKLoginKit, you should avoid Vasily's answer and instead silence the warnings for those specific dependencies.

Option 1

Mention each pods instead of just FacebookCore and add inhibit_warnings: true

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

Option 2

Or silence all pods, by adding to your Podfile this:

inhibit_all_warnings!

Conclusion

You'll still get warnings for your own code. Not getting those could be problematic at some point, that's why I believe it's a better solution.

Next time you update the Facebook sdk, see if you can remove the inhibit_warnings: true or inhibit_all_warnings!.



回答4:

Recently I faced the same issue and @Vasily Bodnarchuk answer seems to be helpful.

However in Continuous integration environments its not possible to change the CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF flag to NO at run time. So in order to isolate the issue i tried by checking all the dependent GEMS installed by Cocoapods and figured out that gem XCODEPROJ version 1.5.7 sets the CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF to YES whenever pod install command is executed. The solution for this is reverting the XCODEPROJ to earlier version 1.5.1 by executing sudo gem install xcodeproj -v 1.5.1 Once reverted just execute pod install and the flag will be set to NO always.



回答5:

This fixes my problem for 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];
       }

   });
}