为什么我需要为某些完成块而不是其他块创建自己的线程安全版本?

时间:2015-01-09 19:24:10

标签: objective-c objective-c-blocks

我有一个UIPageViewController的视图,并且在设置视图控制器的方法中,我使用了一个自我的线程安全实例:

__block typeof(self) threadedSelf = self;

[self.pageController setViewControllers:@[p]
                              direction:UIPageViewControllerNavigationDirectionReverse
                               animated:YES
                             completion:^(BOOL finished){
                                 if (finished) {
                                     [threadedSelf performSelectorOnMainThread:@selector(setNavTitleText) withObject:nil waitUntilDone:NO];
                                 }
                             }];

完成块看起来类似于其他完成块,比如UIView动画方法,但这是第一个完成块,我必须创建一个块版本的self。为什么这种方法与其他完成回调不同?是因为这是一个实例方法,其中UIView动画是一个类(静态)方法吗?

2 个答案:

答案 0 :(得分:1)

这不是一个线程安全问题,它是一个保留周期问题。块保留它们使用的对象。显然,从警告开始,self会保留此块,因此,如果 使用/保留self,那么您有一个保留周期。

你应该在你在块中使用的指针上使用__weak限定符,例如:

__weak typeof(self) weakSelf = self;

__weak__block经常用于出现在块中的变量,但它们有不同的用途。 __weak限定符可防止块保留对象,这正是阻止保留周期所需的工具。 __block限定符确实阻止了块保留对象,但其目的实际上是指示可以在块内更改对象(即,对块内对象所做的更改必须在块外部可见) 。那个不是你的例子中的情况。您引用self但未修改指针(self = foo)。因此,您应该使用__weak限定符而不是__block限定符。

在许多情况下,你既不需要限定词。仅当块实际由块内引用的对象保留时,才会有保留周期。通常,您将使用未拥有的任何对象保留的块,例如:

[UIView animateWithDuration:0.2 animations:^{
    [self makeSomeChangesToBeAnimated];
}];

此处动画块可以安全地引用self而没有限定符,因为self不会保留该块。它可能由 else 保留,但不能由self保留,因此您无需使用__weak限定符。

答案 1 :(得分:0)

如果self保留了引用self的块,我们会有一个保留周期。您试图避免的警告告诉您可能会发生这种情况。我不知道这是不是真的,但是,在明确警告的情况下,我没有机会:我使用“弱强舞”将self的弱版本传递到块中。