如何在xcode中避免这个警告?下面是代码片段:

[player(AVPlayer object) addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
queue:nil usingBlock:^(CMTime time) {
    current+=1;

    if(current==60)
    {
        min+=(current/60);
        current = 0;
    }

    [timerDisp(UILabel) setText:[NSString stringWithFormat:@"%02d:%02d",min,current]];///warning occurs in this line
}];

当前回答

这里对自我的捕捉是伴随着你对自我的隐式属性访问。timerDisp -你不能从一个将被self强保留的块中引用self或self的属性。

你可以通过在你的块中访问timerDisp之前创建一个弱引用来解决这个问题:

__weak typeof(self) weakSelf = self;
[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
                                     queue:nil
                                usingBlock:^(CMTime time) {
                                                current+=1;

                                                if(current==60)
                                                {
                                                    min+=(current/60);
                                                    current = 0;
                                                }

                                                 [weakSelf.timerDisp setText:[NSString stringWithFormat:@"%02d:%02d",min,current]];
                                            }];

其他回答

很多时候,这实际上不是一个保留周期。

如果你知道它不是,你就不需要把没有结果的软弱自我带到这个世界上。

苹果甚至通过他们的UIPageViewController的API将这些警告强加给我们,其中包括一个set方法(触发这些警告-正如在其他地方提到的-认为你正在设置一个值为一个ivar,这是一个块)和一个完成处理程序块(其中你无疑会提到你自己)。

下面是一些编译器指令,可以从这一行代码中删除警告:

#pragma GCC diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
    [self.pageViewController setViewControllers:@[newViewController] direction:navigationDirection animated:YES completion:^(BOOL finished) {
        // this warning is caused because "setViewControllers" starts with "set…", it's not a problem
        [self doTheThingsIGottaDo:finished touchThePuppetHead:YES];
    }];
#pragma GCC diagnostic pop

这里对自我的捕捉是伴随着你对自我的隐式属性访问。timerDisp -你不能从一个将被self强保留的块中引用self或self的属性。

你可以通过在你的块中访问timerDisp之前创建一个弱引用来解决这个问题:

__weak typeof(self) weakSelf = self;
[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
                                     queue:nil
                                usingBlock:^(CMTime time) {
                                                current+=1;

                                                if(current==60)
                                                {
                                                    min+=(current/60);
                                                    current = 0;
                                                }

                                                 [weakSelf.timerDisp setText:[NSString stringWithFormat:@"%02d:%02d",min,current]];
                                            }];
__weak MyClass *self_ = self; // that's enough
self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){
    if (!error) {
       [self_ showAlertWithError:error];
    } else {
       self_.items = [NSArray arrayWithArray:receivedItems];
       [self_.tableView reloadData];
    }
};

有一件非常重要的事情要记住: 不要直接在block中使用实例变量,使用它作为弱对象的属性,示例:

self.loadingDidFinishHandler = ^(NSArray *receivedItems, NSError *error){
        if (!error) {
           [self_ showAlertWithError:error];
        } else {
           self_.items = [NSArray arrayWithArray:receivedItems];
           [_tableView reloadData]; // BAD! IT ALSO WILL BRING YOU TO RETAIN LOOP
        }
 };

别忘了:

- (void)dealloc {
    self.loadingCompletionHandler = NULL;
}

如果传递not retain by anyone对象的弱副本,则会出现另一个问题:

MyViewController *vcToGo = [[MyViewCOntroller alloc] init];
__weak MyViewController *vcToGo_ = vcToGo;
self.loadingCompletion = ^{
    [vcToGo_ doSomePrecessing];
};

如果vcToGo将被释放,然后这个块被发射,我相信你会崩溃,无法识别的选择器到一个垃圾,其中包含vcToGo_变量现在。试着控制它。

更好的版本

__strong typeof(self) strongSelf = weakSelf;

创建弱版本的强引用,作为块中的第一行。如果self在块开始执行时仍然存在,并且没有回落到nil,这一行将确保它在整个块的执行生命周期中持续存在。

所以整个过程是这样的:

// Establish the weak self reference
__weak typeof(self) weakSelf = self;

[player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(0.1, 100)
                                 queue:nil
                            usingBlock:^(CMTime time) {

    // Establish the strong self reference
    __strong typeof(self) strongSelf = weakSelf;

    if (strongSelf) {
        [strongSelf.timerDisp setText:[NSString stringWithFormat:@"%02d:%02d",min,current]];
    } else {
        // self doesn't exist
    }
}];

这篇文章我读过很多遍。这是Erica Sadun写的一篇很棒的文章 如何避免问题时使用块和NSNotificationCenter


迅速更新:

例如,在swift中,一个简单的成功块方法是:

func doSomeThingWithSuccessBlock(success: () -> ()) {
    success()
}

当我们调用这个方法并且需要在成功块中使用self时。我们将使用[弱自我]和守护let特性。

    doSomeThingWithSuccessBlock { [weak self] () -> () in
        guard let strongSelf = self else { return }
        strongSelf.gridCollectionView.reloadData()
    }

这种所谓的强弱舞蹈被流行的开源项目Alamofire所使用。

更多信息请查看swift-style-guide

在提高精度和风格上增加了两分钱。在大多数情况下,你只会在这个块中使用一个或两个self成员,很可能只是更新一个滑块。施展自我是矫枉过正。相反,更好的方法是显式地强制转换块中真正需要的对象。例如,如果它是UISlider*的实例,比如_timeSlider,只需在块声明之前执行以下操作:

UISlider* __weak slider = _timeSlider;

然后在块内使用滑块。从技术上讲,这更精确,因为它将潜在的保留周期缩小到只需要的对象,而不是self内部的所有对象。

完整的例子:

UISlider* __weak slider = _timeSlider;
[_embeddedPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 1)
     queue:nil
     usingBlock:^(CMTime time){
        slider.value = time.value/time.timescale;
     }
];

此外,被强制转换为弱指针的对象很可能已经是self内部的弱指针,这也最小化或完全消除了保留循环的可能性。在上面的例子中,_timeSlider实际上是一个存储为弱引用的属性,例如:

@property (nonatomic, weak) IBOutlet UISlider* timeSlider;

就编码风格而言,与C和c++一样,变量声明最好从右向左阅读。以这种顺序声明SomeType* __weak变量从右到左读起来更自然:variable是指向SomeType的弱指针。