All objects are in the heap, that is obvious, but what about the instance variables?
Do they change the retain count? If yes, can they be directly used and modified in blocks?
I came across a tutorial which says blocks can modify objects that are in the heap. So another question arises: Can we modify a heap object without using
__block before the object type?
You don't need the __block qualifier in order to modify instance variables. You were on the right track in thinking about this. If a thing is on the heap, it's persistent. If it is stack based, like a local variable, it does need to be marked with __block if the block modifies it.
Related
In Objective-C (as of Xcode 7), the __block modifier for use with primitives is clearly explained in Stack Overflow such as here and by Apple here in the Blocks Programming Guide. Without the label, a copy of the primitive is captured and the original cannot be modified from within the block. With the label, no copy, and the original can be modified from within the block.
But for use with pointers to objects, the situation is not so well explained. Here Apple says either “a strong reference is made to self” or “a strong reference is made to the variable”. But then at the end of the page Apple says:
To override this behavior for a particular object variable, you can mark it with the __block storage type modifier.
What does “override this behavior” mean?
Further complicating things is that some posts on Stack Overflow talking about making a weak reference when calling an object from within a block.
I am not trying to establish an object. I just want to modify an existing object’s state from within a block. I believe the block is being called synchronously, within the same thread.
Imagine:
Clicker* myClicker = [[Clicker alloc] init] ;
…
// Declare a block.
void (^myBlock)( );
// Populate the block.
myBlock = ^ void ( ) {
[myClicker click] ; // Updating some state in that object, such as incrementing a counter number or adding an element to a collection.
};
// Call `myBlock` synchronously (same thread) from some other code.
… // … invokes `myBlock` repeatedly …
My questions:
How should that code be modified with __block modifier?
How should that code be modified with weak references?
What other issues apply to an object’s state modified from within a block?
First of all, the basic point of __block is the same for all types of variables (primitive variables, object-pointer variables, and all other variables) -- __block makes the variable shared between the outside scope and the scopes of the blocks that capture it, so that an assignment (=) to the variable in one scope is seen in all other scopes.
So if you don't use __block, if you assign to an object-pointer variable to point to another object outside the block after the block is created, the block won't see the assignment to the variable, and will still see it pointing to the object it was pointing to when the block was created. Conversely, inside the block you won't be able to assign to the variable. If you do use __block, then assignments to the variable to point to another object, either inside or outside the block, will be reflected in the other scopes.
Note that mutation of objects' state has nothing to do with assignment to variables. You mutate objects' state by calling a mutating method on a pointer to the object, or you can alter a field directly using a pointer to the object using the -> syntax. Neither of these involve assigning to a variable holding the pointer to the object. On the other hand, assigning to a variable holding a pointer to an object only makes the pointer point to another object; it does not mutate any objects.
The part you are reading about strong references and "override this behavior" has to do with the separate issue of memory management behavior of blocks under MRC only. Under MRC, there is no concept of variables being __strong or __weak like in ARC. When a variable of object-pointer type is captured by a block in MRC, it is by default captured as a strong reference (the block retains it, and releases it when the block is deallocated), because that is the desired behavior most of the time. If you wanted the block to not retain the captured variable, the only way to do that was to make it __block, which not only made the variable shared between the two scopes, but also made the block not retain the variable. So the two concepts were conflated in MRC.
In ARC, whether a block captures a variable strongly or weakly depends on the captured variable being __strong or __weak (or __unsafe_unretained), and is completely orthogonal with whether the variable is __block or not. You can have object-pointer variables that are __block without being weakly captured, or weakly captured without being __block, or both weakly captured and __block if you want.
You quote the somewhat dated Blocks Programming Topics, which says:
To override this behavior for a particular object variable, you can mark it with the __block storage type modifier.
That document dates back to the days of manual reference counting, back before ARC. In manual reference counting code you could use __block to avoid establishing a strong reference to objects referenced inside the block.
But this behavior has changed with ARC, as outlined in Transitioning to ARC Release Notes. We now use weak in those cases where we don't want to establish strong references to the objects referenced in the block. (You can use unsafe_unretained in special cases where you know the resulting dangling pointer isn't a problem.)
So, go ahead and use __block when dealing with fundamental types that you want to mutate inside the block. But when dealing with objects in blocks under ARC, the __block qualifier generally doesn't enter the discussion. The question is simply whether you want a strong reference or a weak one (or an unsafe, unretained one). And that's largely dictated by the object graph of your app, namely (a) whether you need weak/unretained reference to prevent strong reference cycle; or (b) you don't want want some asynchronously executing block to unnecessarily prolong the life of some object referenced in the block. Neither of those situations would appear to be the case here.
I read that if block wants to modify a variable outside, this variable has to be described by using keyword __block since it has to be copied to heap with block itself.
But what if I do not want to use __block and still get to modify the variable, is there a way?
I did some thinking that maybe I can set that variable to global or static instead of an auto one so that it will be stored in static memory area.
Or can I set it to pointer and point to some content which is allocated on heap? I tried this case which didn't work, I would like to know why.
Essentially, in order to avoid losing the variable, block would copy the local variable onto heap if you would like to access and modify the variable. But if you make the variable global or static, which would be stored on global region and you don't need to worry losing it on stack, block wouldn't copy it but is able to modify it directly.
Please correct me if any mistake and I will mark myself answer if there isn't any better one.
I've recently come across an Apple document that shows the following property declaration for a block:
#interface XYZObject : NSObject
#property (copy) void (^blockProperty)(void);
#end
Also, this article states:
Note: You should specify copy as the property attribute, because a block needs to be copied to keep track of its captured state outside of the original scope. This isn’t something you need to worry about when using Automatic Reference Counting, as it will happen automatically, but it’s best practice for the property attribute to show the resultant behavior. For more information, see Blocks Programming Topics.
I also read the suggested Blocks Programming Topics but haven't found anything relevant there.
I'm still curious as to why defining a block property as "copy" is best practice. If you have a good answer, please try to distinguish between ARC and MRC differences if there are any.
Thank you
By default blocks are created on the stack. Meaning they only exist in the scope they have been created in.
In case you want to access them later they have to be copied to the heap by sending a copy message to the block object. ARC will do this for you as soon as it detects a block needs to be accessed outside the scope its created in. As a best practise you declare any block property as copy because that's the way it should be under automatic memory management.
Read Stack and Heap Objects in Objective-C by Mike Ash for more info on stack vs. heap.
Blocks are, by default, allocated on the stack. This is an optimization, since stack allocation is much cheaper than heap allocation. Stack allocation means that, by default again, a block will cease to exist when the scope in which it is declared exits. So a block property with retain semantics will result in a dangling pointer to a block that doesn't exist anymore.
To move a block from the stack to the heap (and thus give it normal Objective-C memory management semantics and an extended lifetime), you must copy the block via [theBlock copy], Block_copy(theBlock), etc. Once on the heap, the block's lifetime can be managed as needed by retaining/releasing it. (Yes, this applies in ARC too, you just don't have to call -retain/-release yourself.)
So you want to declare block properties with copy semantics so the block is copied when the property is set, avoiding a dangling pointer to a stack-based block.
The "best practices" you refer to simply say, "Seeing as ARC is going to magically copy your block no matter what you write here, it's best you explicitly write 'copy' so as not to confuse future generations looking at your code."
Explanation follows:
Typically, you shouldn’t need to copy (or retain) a block. You only need to make a copy when you expect the block to be used after destruction of the scope within which it was declared. Copying moves a block to the heap.
–Blocks Programming Topics: Using Blocks, Copying Blocks
Clearly, assigning a block to a property means it could be used after the scope it was declared in has been destroyed. Thus, according to Blocks Programming Topics that block should be copied to the heap with Block_copy.
But ARC takes care of this for you:
Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more.
–Transitioning to ARC
Note that this isn't about the retain semantics the block. There's simply no way for the block's context to exist without being moved off the (soon-to-be-popped) stack and on to the heap. So regardless of what attributes you qualify your #property with, ARC is still going to copy the block.
I'm currently having trouble understanding the fundamentals of Obj-C blocks and the __block storage type. From the following documentation:
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6
I'm trying to understand the following paragraph and examples:
When a block is copied, it creates strong references to object variables used within the block. If you use a block within the implementation of a method:
If you access an instance variable by reference, a strong reference is made to self;
If you access an instance variable by value, a strong reference is made to the variable.
The following examples illustrate the two different situations:
dispatch_async(queue, ^{
// instanceVariable is used by reference, a strong reference is made to self
doSomethingWithObject(instanceVariable);
});
id localVariable = instanceVariable;
dispatch_async(queue, ^{
/*
localVariable is used by value, a strong reference is made to localVariable
(and not to self).
*/
doSomethingWithObject(localVariable);
});
To override this behavior for a particular object variable, you can mark it with the __block storage type modifier.
My questions:
How exactly is one example "accessed by reference" while the other one is accessed by variable? Why is localVariable "used by value?"
What does the doc mean by "a strong reference is made to self"? Which "self" is it referring to?
If I add the __block storage type to localVariable in the second example, am I wrong to assume that the block closes over the variable, so it keeps it around in heap until block is released? What other things are happening?
Thank you!
How exactly is one example "accessed by reference" while the other one is accessed by variable? Why is localVariable "used by value?"
One way to understand this is the following:
when you use a local variable in a block defined in the method, what happens is that the content of the variable is copied in some block private memory, so that it is available when the block is executed (after the method exits); in this sense we may talk of accessed "by value" (as in: the value is copied); syntactically the compiler doesn't know what the content of localVariable refers to, so its values is treated as such;
when directly accessing instanceVariable in a block defined within a method of a class, the compiler knows that we are accessing the same object that is executing the method and there is not need to copy anything, since the object has a longer lifetime than the method where the block is found; but we need to ensure that the object is still there when the block is executed, so we get a strong reference to it.
Now, as to the use of "by reference": in the first case, you get a copy of the reference to the class member: if you could change its value (but you can't, because the compiler forbids it), you were just modifying a block private copy, so the original object is not affected.
In the second case, you can modify the value of instanceVariable (like in: it was nil and you allocate an object referred through it) and this will affect the object that executed the method were the block is defined.
What does the doc mean by "a strong reference is made to self"? Which "self" is it referring to?
self is the object which is currently executing the method where the block is found. that a strong reference is made only means (in ARC parlance) that the retain count of the object is incremented (to make sure some other entity cannot cause it to be deallocated by releasing it).
If I add the __block storage type to localVariable in the second example, am I wrong to assume that the block closes over the variable, so it keeps it around in heap until block is released? What other things are happening?
Using __block makes the variable be always accessed "by reference", so you can modify them.
This is how they are handled:
__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or created within the variable’s lexical scope. Thus, the storage will survive the destruction of the stack frame if any copies of the blocks declared within the frame survive beyond the end of the frame (for example, by being enqueued somewhere for later execution). Multiple blocks in a given lexical scope can simultaneously use a shared variable.
As an optimization, block storage starts out on the stack—just like blocks themselves do. If the block is copied using Block_copy (or in Objective-C when the block is sent a copy), variables are copied to the heap. Thus, the address of a __block variable can change over time.
I understand that the call to CLGeocoder geocodeAddressString is asynchronous, with a block passed in to handle the callback at completion time. I also understand that the only variables that are mutable within the block are local __block variables. But I need to store the resulting CLPlacemarks in a global NSMutableArray variable, and I can't work out how that can happen. Any __block variables can only be accessed within the same method, but at the point that they have any value (i.e. within the block) I can't assign any value to the global array. After the block, the __block variables will likely not have any value because of the immediate return when calling the async geocodeAddressString.
How can I store the results of the call, so that they can be used to update a UITableView?
Ok, solved. I was incorrectly deducing (from my reading about blocks) that properties and instance variables could not be modified within the scope of a block. In my case, the reason I couldn't modify my iVar array was that I hadn't alloc/init'ed it. Once I did that, I was able to assign values and see them outside of the block e.g. in my cellForRowAtIndexPath method of my table view.
Apologies to anyone who may have been misled by my initial assumptions! For the record, I do think that the text on the Apple docs re blocks & variables here is a bit misleading...the only variables that it mentions as being mutable are the __block function-level variables, whereas it says all others "can be accessed" which I took as meaning "read-only" (I know that both getters and setters are accessors, but the context was confusing).