ARC __block and __weak

Let's say I'm trying to access self from inside a block:

 [someObject successBlock:^(NSArray *result) { [self someSuccessMethod]; } failure:^(NSString *errorMessage, int status) { [self someFailureMethod]; }]; 

I understand that this creates a save loop and that someObject and self will never be released.

What scares me is what actually happens with / without the __block . I can fix the save loop by making the __weak link for myself:

 __weak MyClass* me = self; [someObject successBlock:^(NSArray *result) { [me someSuccessMethod]; } failure:^(NSString *errorMessage, int status) { [me someFailureMethod]; }]; 

I do not need to use __block here because I am not trying to change me from inside the block. From what I understand, if I do not use __block , a copy of me indicated in the block. My question is: if what is mentioned inside the block is just a copy of the object, why does the source code block create a save loop? I would suggest that the self reference is just a copy, since I never use the __block keyword. Am I thinking about it wrong?

+7
ios objective-c automatic-ref-counting
source share
4 answers

In the first case, the block captures self , i.e. saves a copy of self as another strong pointer. This increases the number of holds of the pointed object and causes a save cycle.

In the second case, the block captures me , i.e. saves a copy of me as another weak pointer. This does not increase the number of holds and therefore does not cause hold cycles.

(If you print the address me outside and inside the block, you will see that the addresses are different. The block has its own weak pointer to the object.)

If the selected object is crossed out, all weak references (including saved blocks) are set to nil in the Objective-C runtime.

(I just hope I'm right.)

+7
source share

Saving a loop occurs when two objects store a strong link to each other. The simplest case is object a , which stores a strong reference to object b and b , doing the opposite [1]. Saving loops is a problem in Objective-C because they make ARC believe that these objects are always used, even if these objects are not referenced anywhere.

Let's look at a few examples. You have a z object that selects a and b , uses them, and then removes them. If a and b created the save cycle between themselves in the first place, a and b will not be released. If you do this several times, you will seriously leak the memory.

Another real-life example of a save loop is if a highlights and strongly refers to an object b , but you also keep a strong link from b to a (many smaller objects in the object graph may need to access their parents).

The most common solutions in these cases would be to make sure that the objects contained in them have only weak references to its containing objects, and also make sure that the twin objects do not contain strong references to each other.

Another solution (usually less elegant, but perhaps appropriate in some situations) might have some kind of custom cleanup method in a that references b . That way, b will be freed up when calling cleanup (unless b is mentioned elsewhere). This is cumbersome because you cannot do this from a dealloc (it is never called if there is a save cycle), and because you must remember to call cleanup at the appropriate times.

  • Note that save loops are also transitive (for example, the object a strongly references b , which strongly refers to c , which strongly refers to a ).

With all this, it says: managing memory blocks is pretty hard to understand.

In the first example, you can create a temporary save loop (and only if your self object stores a strong reference to someObject ). This time save cycle leaves when the block completes execution and is freed.

At runtime, self will again retain a reference to someObject , someObject to block and block to self . But again, this is temporary because the block is not permanently stored somewhere (unless the [someObject successBlock:failure:] implementation does this, but it is not often found for completion blocks).

So the save loop is not a problem in your first example.

As a rule, saving loops inside blocks is a problem only if some object stores the block rather than executing it directly. Then it’s easy to see that self refers strongly to block , and block has a strong reference to self . Note that accessing any ivar from the inside automatically generates a strong self reference in this block.

Equivalent to the fact that the contained object has no special relation to its container, uses __weak SelfClass *weakSelf = self to access both methods and ivars (it is better if you access ivars through accessors, as when using properties). Your block reference to self will be weak (this is not a copy , it is a weak link ), and this will allow self free itself if it stops linking strongly.

It can be argued that in practice it is recommended that you always use weakSelf inside all blocks, stored or not, just in case. I wonder why Apple did not do this by default. Doing this usually does nothing harmful to the block code, even if not actually used.


__block rarely used for variables that point to objects, since Objective-C does not ensure the immutability of such objects.

If you have a pointer to an object, you can call its methods, and these methods can change it, with or without __block . __block bigger (only?) useful for variables of basic types (int, float, etc.). See here what happens when you use __block with an object pointer variable. You can also learn more about __block 's __block Blocking Programming Themes .

Edit: Fixed bug with using __block using object pointers. Thanks @KevinDiTraglia for pointing this out.

+4
source share

In your first example, a save loop will never be created. There will be a save cycle, everything is fine, but as soon as the blocks are executed, the reference form of blocks in someObject will be deleted. This way, someObject will live, at least until the blocks are executed. Such a save time cycle can be good or bad, depending on what you want:

If you need your someObject alive, at least until the completion of its blocks, everything is fine. However, if there is no reason to save this object, you must implement it using a "weak" link.

Eg. myObject is a view controller that extracts an image from the network in these blocks. If you place this someObject form of the navigation controller, the controller will not be able to display the image after it is extracted, so there is no need to save it. Success or error is irrelevant, the user is no longer interested in the someObject image that should have been received. In this case, using weak is the best option, but the code in the blocks should expect that self may be nil.

+3
source share

You can specify "I" as an argument to the block, by specifying the variable name "self" exactly, this will protect against self-service in the block.

And you have "someObject and I never get de-allocateded": self will be released when the blocks are freed. Blocks will be freed using some object. SomeObject will be released if it no longer has links. Therefore, if your self-object owns someObject, just release someObject when you no longer need it.

0
source share

All Articles