1
votes

I have a view with a UIPageViewController and on the method to set view controllers I have use a thread safe instance of self like this:

__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];
                                 }
                             }];

The completion block looks similar to other completion blocks, like the UIView animation method, but this is the first completion block where I've had to create a block version of self. Why is this method different than other completion callbacks? Is it because this is an instance method where the UIView animation is a class (static) method?

2
Can you explain why you think you need threadedSelf in the first place? You are making an initial assumption here; why? Is it because setViewControllers is being called on a background thread? If so, why are you doing that? - matt
If I don't set it with a block I get a warning: "Capturing 'self' strongly in this block is likely to lead to a retain cycle". I'm sure I could do the same thing with __weak instead of __block but all the examples I've seen for this method on UIPageViewController specifically use __block. - Jake Hargus
But that has nothing to do with "threaded". It has to do with memory management. That's exactly what I'm asking. Is the question that you don't understand what a weak reference is - why you need one here, and how to get one? - matt
ah gotcha. I got some of this from a tutorial where they listed the variable as "threadsafe" in their explanation. I guess that's not really the case. I know what a weak reference is, I wasn't sure about the __block reference though or why this reference has to be managed differently than other completion blocks. - Jake Hargus
Weak references are threadsafe if you do the weak-strong dance, which I point you to in my comment on my answer. The reason is that if self were to vanish out from under you, the weak-strong dance allows you to detect safely the resulting nil weak ref and go no further. I have never seen __block used in that way and it is not what Apple officially recommends in their WWDC videos; they do the weak-strong dance (and they even call it that; I believe they got that name from me, but I could be wrong, maybe it existed before I started using it :) m. - matt

2 Answers

1
votes

This isn't really a thread safety issue, it's a retain cycle issue. Blocks retain the objects they use. Evidently, from the warning, this block is being retained by self, so if it also uses/retains self then you have a retain cycle.

You should use the __weak qualifier on the pointer to self that you use in the block, like:

__weak typeof(self) weakSelf = self;

Both __weak and __block are frequently used for variables that will appear in blocks, but they have different purposes. The __weak qualifier prevents the block from retaining the object and is exactly the tool you need to prevent a retain cycle. The __block qualifier does prevent the block from retaining the object, but its purpose is really to indicate that the object might be changed inside the block (i.e. changes made to the object inside the block must be visible outside of the block). That is not the case in your example. You refer to self but you are not modifying the pointer (self = foo). Therefore you should use the __weak qualifier instead of the __block qualifier.

In many cases you need neither qualifier. There will be a retain cycle only if the block is actually retained by an object referred to inside the block. Frequently, you will use blocks that are not retained by any object you own, for example:

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

Here the animation block can safely refer to self with no qualifier, because the block is not retained by self. It might be retained by something else but not by self, so you do not need to use the __weak qualifier.

0
votes

If self retains a block that refers to self, we have a retain cycle. The warning you are trying to avoid is telling you that that might happen here. I don't know whether it's true or not but, given the explicit warning, I take no chances: I pass a weak version of self into the block, using the "weak-strong dance".