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.
Related
Are there any conditions in Objective-C (Objective-C++) where the compiler can detect that a variable capture in a block is never used and thus decide to not capture the variable in the first place?
For example, assume you have an NSArray that contains a large number of items which might take a long time to deallocate. You need to access the NSArray on the main thread, but once you're done with it, you're willing to deallocate it on a background queue. The background block only needs to capture the array and then immediately deallocate. It doesn't actually have to do anything with it. Can the compiler detect this and, "erroneously", skip the block capture altogether?
Example:
// On the main thread...
NSArray *outgoingRecords = self.records;
self.records = incomingRecords;
dispatch_async(background_queue, ^{
(void)outgoingRecords;
// After this do-nothing block exits, then outgoingRecords
// should be deallocated on this background_queue.
});
Am I guaranteed that outgoingRecords will always be captured in that block and that it will always be deallocated on the background_queue?
Edit #1
I'll add a bit more context to better illustrate my issue:
I have an Objective-C++ class that contains a very large std::vector of immutable records. This could easily be 1+ million records. They are basic structs in a vector and accessed on the main thread to populate a table view. On a background thread, a different set of database records might be read into a separate vector, which could also be quite large.
Once the background read has occurred, I jump over to the main thread to swap Objective-C objects and repopulate the table.
At that point, I don't care at all about the contents of the older vector or its parent Objective-C class. There's no fancy destructors or object-graph to teardown, but deallocating hundreds of megabytes, maybe even gigabytes of memory is not instantaneous. So I'm willing to punt it off to a background_queue and have the memory deallocation occur there. In my tests, that appears to work fine and gives me a little bit more time on the main thread to do other stuff before 16ms elapses.
I'm trying to understand if I can get away with simply capturing the object in an "empty" block or if I should do some sort of no-op operation (like call count) so that the compiler cannot optimize it away somehow.
Edit #2
(I originally tried to keep the question as simple as possible, but it seems like it's more nuanced then that. Based on Ken's answer below, I'll add another scenario.)
Here's another scenario that doesn't use dispatch_queues but still uses blocks, which is the part I'm really interested in.
id<MTLCommandBuffer> commandBuffer = ...
// A custom class that manages an MTLTexture that is backed by an IOSurface.
__block MyTextureWrapper *wrapper = ...
// Issue some Metal calls that use the texture inside the wrapper.
// Wait for the buffer to complete, then release the wrapper.
[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> cb) {
wrapper = nil;
}];
In this scenario, the order of execution is guaranteed by Metal. Unlike the example above, in this scenario performance is not the issue. Rather, the IOSurface that is backing the MTLTexture is being recycled into a CVPixelBufferPool. The IOSurface is being shared between processes and, from what I can tell, MTLTexture does not appear to increase the useCount on the surface. My wrapper class does. When my wrapper class is deallocated, the useCount is decremented and the bufferPool is then free to recycling the IOSurface.
This is all working as expected but I end up with silly code like above just out of uncertainty whether I need to "use" the wrapper instance in the block to ensure it's captured or not. If the wrapper is deallocated before the completion handler runs, then the IOSurface will be recycled and the texture will get overwritten.
Edit to address question edits:
From the Clang Language Specification for Blocks:
Local automatic (stack) variables referenced within the compound
statement of a Block are imported and captured by the Block as const
copies. The capture (binding) is performed at the time of the Block
literal expression evaluation.
The compiler is not required to capture a variable if it can prove
that no references to the variable will actually be evaluated.
Programmers can force a variable to be captured by referencing it in a
statement at the beginning of the Block, like so:
(void) foo;
This matters when capturing the variable has side-effects, as it can
in Objective-C or C++.
(Emphasis added.)
Note that using this technique guarantees that the referenced object lives at least as long as the block, but does not guarantee it will be released with the block, nor by which thread.
There's no guarantee that the block submitted to the background queue will be the last code to hold a strong reference to the array (even ignoring the question of whether the block captures the variable).
First, the block may in fact run before the context which submitted it returns and releases its strong reference. That is, the code which called dispatch_async() could be swapped off the CPU and the block could run first.
But even if the block runs somewhat later than that, a reference to the array may be in an autorelease pool somewhere and not released for some time. Or there may be a strong reference someplace else that will eventually be cleared but not under you explicit control.
I am trying to convert an iOS project into ARC.
I am using the compiler flag for some of the files.
But one of the files contains a variable declared within a method like the following:
aClass **obj;
With ARC turned off, it gives an error:
"pointer to non-const type without explicit ownership"
I could silence the warning by doing this:
aClass *__strong* obj;
Which I believe is not a good practice as far as ownership is concerned.
But the error didn't exist in non-ARC environment.
My question is simply as follows:
How would I change from non-ARC to ARC setup the declaration of the object without having to use *__strong*?
i.e., how could I declare (or make changes to declaring) aClass **obj under ARC without have to use *__strong*, which I am sure I have read somewhere it is not a good practice to do but I forgot where I read it.
And:
Why didn't it give error under non-ARC environment.
TL;DR: You probably don't want a pointer to a pointer unless you can avoid it. It's pretty poor design to do so under a system where memory is managed for you. This answer explains more: Pointer to a pointer in objective-c?.
More Details
Under non-ARC, the system leaves retain/release up to you so it doesn't matter who owns a pointer. You, the programmer, owns it. In ARC land, the system needs to know when to retain or release, and it can't always infer which class/object has ownership over a particular object. Other classes may need the reference but the class that declared it is done with the object already. Basically, the __strong tells the declaring class that it should be in charge of managing the pointer. It 'overrides' the ownership of the pointer in a way. So that's a way to get around it. The best way to get around it would be to refactor the code to not use explicitly managed memory, but how you've fixed it will work if that's not possible/too hard.
When I have a TList (so, a list of "reference to procedure"), and I Clear it, do all the captured variables used in the anonymous methods get freed, so no leaking occurs?
Ie. is reference counting in effect upon clearing the TList?
Delegate types are reference counted like interfaces (in fact they are implemented as interfaces). That means if they run out of scope the object behind the scenes (you might have seen that ArcRec$xxxx thing mentioned somewhere - that is the class name the compiler generates) gets destroyed. Captured variables are implemented as fields inside that class so they also run out of scope and are getting freed.
However you might pay attention to some circular referencing which might cause a memory leak with captured variables because of some important fact:
If you have multiple anonymous methods inside a single routine/method they all are implemented by one single class (that ArcRec$xxxx thing). So in this case the anonymous method with the longest lifetime might keep another one alive even if that already is out of scope.
I encountered this thing in a book which I am reading and it got me thinking:
"When you allocate a block, it is created on the stack. This means that, even if you were to keep a strong reference to it, calling it later would result in a crash because the memory would be destroyed as soon as you leave the method in which it was defined."
I thought if I have a strong pointer to something, it is kept alive?
Does this mean this does not apply for objects allocated on the stack?
I am trying to think of an example without using blocks...(e.g., of pointer - maybe an ivar- pointing to a stack allocated object which gets destroyed even though the pointer is alive)
Objects are never allocated on the stack in Objective-C. Blocks are special however, since they are stack allocated. So if you want to retain a pointer to a block, you must first copy it by using Block_copy and use the copy, then release it with Block_release. This must be done if the block is to be used after the scope it was declared in is destroyed. More on the matter here: https://developer.apple.com/library/mac/documentation/cocoa/Conceptual/Blocks/Articles/bxUsing.html (under "Copying Blocks"). Yet again though, this does not apply to regular objects.
Blocks can be messaged like objects. To move them from the stack to the heap, just "copy" them.
void (^stackBlock)() = [^(){
NSLog(#"Hello world");
} copy];
~ Will ARC always release an object the line after the last strong pointer is removed? Or is it undetermined and at some unspecified point in the future it will be released? Similarly, assuming that you don't change anything with your program, will ARC always be the same each time you run and compile your program?
~ How do you deal with handing an object off to other classes? For example, suppose we are creating a Cake object in a Bakery class. This process would probably take a long time and involve many different methods, so it may be reasonable for us to put the cake in a strong property. Now suppose we want to hand this cake object off to a customer. The customer would also probably want to have a strong pointer to it. Is this ok? Having two classes with strong pointers to the same object? Or should we nil out the Bakery's pointer as soon as we hand off?
Your code should be structured so the answer to this doesn't matter - if you want to use an object, keep a pointer to it, don't rely on ARC side effects to keep it around :) And these side effects might change with different compilers.
Two strong pointers is absolutely fine. ARC will only release the object when both pointers are pointing to something else (or nothing!)
ARC will implement the proper retains and releases at compile time. It will not behave any different than if you put them in there yourself so it will always do the same compilation and to answer your question should always behave the same. But that said it does not mean that your object will always be released immediately after the pointer is removed. Because you never call dealloc directly in any form of objective C you are only telling it that there is no reference count and that it is safe to release. This usually means that it will be released right away though.
If you pass an object from one class to another and the receiving class has a strong property associated with it and the class that passes it off eventually nils its pointer it will still have a reference count of at least 1 and will be fine.
Ok, first this answer might helpt you also a little bit: ARC equivalent of autorelease?
Generally after the last strong variable is nilled, the object is released immediately. If you store it in a property, you can nil the property, assign it to something like __strong Foo *temp = self.bar; before you nil, and return that local __strong variable (although arc normally detects the return, and inferes the __strong byitself).
Some more details on that: Handling Pointer-to-Pointer Ownership Issues in ARC
DeanWombourne's answer is correct; but to add to (1).
In particular, the compiler may significantly re-order statements as a part of optimization. While method calls will always occur in the order written in code (because any method call may have side effects), any atomic expression may be re-ordered by the compiler as long as that re-order doesn't impact behavior. Same thing goes for local variable re-use, etc...
Thus, the ARC compiler will guarantee that a pointer is valid for as long as it is needed, no more. But there is no guarantee when the pointed to object might be released other than that it isn't going to happen beyond the scope of declaration. There is also no guarantee that object A is released before B simply because A is declared and last used before B.
IN other words, as long as you write your code without relying on side effects and race conditions, it should all just work.
Please keep you code proper as it has diffrent behaviour on diffrent complier.