Examine the following code, and assume it was compiled under ARC:
- (void)foo {
NSOperationQueue *oq = [[NSOperationQueue alloc] init];
[oq addOperationWithBlock:^{
// Pretend that we have a long-running operation here.
}];
}
Although the operation queue is declared as a local variable, its lifetime continues beyond the scope of the method as long as it has running operations.
How is this achieved?
UPDATE:
I appreciate Rob Mayoff's well-thought-out comments, but I think I did not ask my question correctly. I am not asking a specific question about NSOperationQueue, but rather a general question about object lifetime in ARC. Specifically, my question is this:
How, under ARC, can an object participate in the management of its own lifetime?
I've been a programmer for a very long time, and I'm well aware of the pitfalls of such a thing. I am not looking to be lectured as to whether this is a good or bad idea. I think in general it is a bad one. Rather, my question is academic: Whether it's a good or bad idea or not, how would one do this in ARC and what is the specific syntax to do so?
As a general case you can keep a reference to yourself. E.g.:
#implementation MasterOfMyOwnDestiny
{
MasterOfMyOwnDestiny *alsoMe;
}
- (void) lifeIsGood
{
alsoMe = self;
}
- (void) woeIsMe
{
alsoMe = nil;
}
...
#end
Here are a few possibilities:
The NSOperationQueue retains itself until it is empty, then releases itself.
The NSOperationQueue causes some other object to retain it. For example, since NSOperationQueue uses GCD, perhaps addOperationWithBlock: looks something like this:
- (void)addOperationWithBlock:(void (^)(void))block {
void (^wrapperBlock)(void) = ^{
block();
[self executeNextBlock];
};
if (self.isCurrentlyExecuting) {
[self.queuedBlocks addObject:wrapperBlock];
} else {
self.isCurrentlyExecuting = YES;
dispatch_async(self.dispatchQueue, wrapperBlock);
}
}
In that code, the wrapperBlock contains a strong reference to the NSOperationQueue, so (assuming ARC), it retains the NSOperationQueue. (The real addOperationWithBlock: is more complex than this, because it is thread-safe and supports executing multiple blocks concurrently.)
The NSOperationQueue doesn't live past the scope of your foo method. Maybe by the time addOperationWithBlock: returns, your long-running block has already been submitted to a GCD queue. Since you don't keep a strong reference to oq, there is no reason why oq shouldn't be deallocated.
In the example code give, under ARC, the NSOperationQueue, being local to the enclosing lexical scope of the block, is captured is captured by the block. Basically, the block saves the value of the pointer so it can be accessed from within the block later. This actually happens regardless of whether you're using ARC or not; the difference is that under ARC, object variables are automatically retained and released as the block is copied and released.
The section "Object and Block Variables" in the Blocks Programming Topics guide is a good reference for this stuff.
The simplest thing I can think of would be to have a global NSMutableArray (or set, or whatever) that the object adds itself to and removes itself from. Another idea would be to put the (as you've already admitted) oddly-memory-managed code in a category in a non-ARC file and just use -retain and -release directly.
Related
I have an Objective-C class whose instances can detect when they are no longer needed and destroy themselves, but I am looking for a safe way to trigger an object's self-destruction from within the object itself, without somehow "destroying the method that is calling the destruction"... My code looks roughly like this (some removed for brevity):
+ (oneway void)destroyInstance:(id)obj {
printf("Destroying.\n");
if (obj != nil) {
free(obj);
obj = nil;
}
}
- (oneway void)release {
_noLongerRequired = [self determineIfNeeded]; // BOOL retVal
if (_noLongerRequired) {
[self deallocateMemory]; // Free ivars etc (NOT oneway)
[MyClass destroyInstance:self]; // Oneway
}
}
If I call -release, it should return instantly to the main thread (due to the oneway).
Meanwhile, if the instance finds it is no longer needed, it should then call the oneway class method destroyInstance: and remove itself from the runtime. My question is, is this safe?? And have I used oneway correctly? It seems to me there is the possibility of destroying the instance's -release function before it returns, which could be... rather bad..?
(PS: Obviously not looking for anything to do with NSObject, etc :))
This is without a doubt a terrible idea if you want working and maintainable software and unsafe in just about any context. But sometimes terrible, unsafe ideas can be fun on the weekend, so I'll answer the components of the question I can discern.
A method will not get "destroyed" because an instance is deallocated. What can happen is that self can end up pointing to deallocated memory during the execution of a method, which means that accessing self or any instance variables during this time can crash.
As to the rest of your code, there is no reason at all to set obj equal to nil in +destroyInstance, so if you were trying accomplish something in particular (nil'ing out pointers to the object perhaps) that way is not the right way to go about it.
Thinking about the use of oneway, what the language says is that sending this message won't block the calling thread. In the context of releasing objects I think it makes some sense, as presumably the target of the message won't ever be referenced by that thread again. By that logic I'd think your declaration of +destroyInstance is maybe OK. I do wonder if you'd need to provide some sort of synchronization so that there's no retain/release race conditions but thinking about it, taking ownership of an object should probably never be asynchronous.
My personal opinion is that anyone who puts this code into production should probably be fired or sued =P. But if it's only for educational purposes, have fun, and hope this helps.
In wikipedia example author has released the object stats, when it has not been allocated, copied, or retained. Is this an error or something I don't understood?
- (IBAction)analyzeDocument:(NSButton *)sender
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSDictionary *stats = [myDoc analyze];
dispatch_async(dispatch_get_main_queue(), ^{
[myModel setDict:stats];
[myStatsView setNeedsDisplay:YES];
[stats release];
});
});
}
It is either an error or it is properly documented that analyze returns ownership of the object to the caller. If it is not an error that stats is released then that codes example is using a convention that goes against Apple's memory management rules for ownership.
Memory-management rules, sometimes referred to as the ownership
policy, help you to explicitly manage memory in Objective-C code.
You own any object you create by allocating memory for it or copying
it.
Related methods: alloc, allocWithZone:, copy, copyWithZone:,
mutableCopy, mutableCopyWithZone:
Another prefix that should return ownership is the class method +new. E.g. [MyDocClass newAnalysis];
This is just an example cooked up by John Siracusa to demonstrate how GCD can easily put a long-running task into the background, but, yes, it has one of two problems, one an ingored convention, the other an actual error.
It's possible that the fictional analyze method returns an owning reference. This is a violation of Cocoa convention that methods not named new, alloc, release, or copy... generally don't return such references, but if the documentation made clear that it did, and there was really no way around it, it could be all right. In this case, sending release to stats would be necessary to avoid a memory leak. (If this were real code, renaming the method would be a good idea, perhaps using create which is used in CoreFoundation to signify return of an owning reference.)
If, however, analyze follows convention and returns a non-owned reference, then you're right, sending release to stats is incorrect and will eventually cause a crash.
Most likely analyze is returning a dictionary with a retain count of 1 which is why the release is needed.
When compiling with ARC, method arguments often appear to be retained at the beginning of the method and released at the end. This retain/release pair seems superfluous, and contradicts the idea that ARC "produces the code you would have written anyway". Nobody in those dark, pre-ARC days performed an extra retain/release on all method arguments just to be on the safe side, did they?
Consider:
#interface Test : NSObject
#end
#implementation Test
- (void)testARC:(NSString *)s
{
[s length]; // no extra retain/release here.
}
- (void)testARC2:(NSString *)s
{
// ARC inserts [s retain]
[s length];
[s length];
// ARC inserts [s release]
}
- (void)testARC3:(__unsafe_unretained NSString *)s
{
// no retain -- we used __unsafe_unretained
[s length];
[s length];
// no release -- we used __unsafe_unretained
}
#end
When compiled with Xcode 4.3.2 in release mode, the assembly (such that I'm able to understand it) contained calls to objc_retain and objc_release at the start and end of the second method. What's going on?
This is not a huge problem, but this extra retain/release traffic does show up when using Instruments to profile performance-sensitive code. It seems you can decorate method arguments with __unsafe_unretained to avoid this extra retain/release, as I've done in the third example, but doing so feels quite disgusting.
See this reply from the Objc-language mailing list:
When the compiler doesn't know anything about the
memory management behavior of a function or method (and this happens a
lot), then the compiler must assume:
1) That the function or method might completely rearrange or replace
the entire object graph of the application (it probably won't, but it
could). 2) That the caller might be manual reference counted code, and
therefore the lifetime of passed in parameters is not realistically
knowable.
Given #1 and #2; and given that ARC must never allow an object to be
prematurely deallocated, then these two assumptions force the compiler
to retain passed in objects more often than not.
I think that the main problem is that your method’s body might lead to the arguments being released, so that ARC has to act defensively and retain them:
- (void) processItems
{
[self setItems:[NSArray arrayWithObject:[NSNumber numberWithInt:0]]];
[self doSomethingSillyWith:[items lastObject]];
}
- (void) doSomethingSillyWith: (id) foo
{
[self setItems:nil];
NSLog(#"%#", foo); // if ARC did not retain foo, you could be in trouble
}
That might also be the reason that you don’t see the extra retain when there’s just a single call in your method.
Passing as a parameter does not, in general, increase the retain count. However, if you're passing it to something like NSThread, it is specifically documented that it will retain the parameter for the new thread.
So without an example of how you're intending to start this new thread, I can't give a definitive answer. In general, though, you should be fine.
Even the answer of soul is correct, it is a bit deeper than it should be:
It is retained, because the passed reference is assigned to a strong variable, the parameter variable. This and only this is the reason for the retain/release pair. (Set the parameter var to __weak and what happens?)
One could optimize it away? It would be like optimizing every retain/release pairs on local variables away, because parameters are local variables. This can be done, if the compiler understands the hole code inside the method including all messages sent and functions calls. This can be applied that rarely that clang even does not try to do it. (Imagine that the arg points to a person (only) belonging to a group and the group is dealloc'd: the person would be dealloc'd, too.)
And yes, not to retain args in MRC was a kind of dangerous, but typically developers know their code that good, that they optimized the retain/release away without thinking about it.
It will not increment behind the scenes. Under ARC if the object is Strong it will simply remain alive until there are no more strong pointers to it. But this really has nothing to do with the object being passed as a parameter or not.
When writing a method that accepts a block as an argument, do I need to do anything special such as copying the block to the heap before executing it? For example, if I had the following method:
- (void)testWithBlock:(void (^)(NSString *))block {
NSString *testString = #"Test";
block(testString);
}
Should I do anything with block before calling it, or when entering the method? Or is the above the correct way of using the passed-in block? Also, is the following way of calling the method correct, or should I do something with the block before passing it?
[object testWithBlock:^(NSString *test){
NSLog(#"[%#]", test);
}];
Where do I need to copy the block? And how would this have been different if I wasn't using ARC?
When you receive a block as a method parameter, that block could be the original that had been created on the stack or it could be copy (a block on the heap). As far as I'm aware, there's no way tell. So the general rule of thumb is if you're going to execute the block within the method that's receiving it, you don't need to copy it. If you intend to pass that block to another method (which may or may not execute it immediately) then you also don't need to copy it (the receiving method should copy it if it intends to keep it around). However, if you intend to store the block in any way for some place for later execution, you need to copy it. The primary example many people use is some sort of completion block held as an instance variable:
typedef void (^IDBlock) (id);
#implementation MyClass{
IDBlock _completionBlock;
}
However, you also need to copy it if you're going to add it to any kind of collection class, like an NSArray or NSDictionary. Otherwise, you'll get errors (most likely EXC_BAD_ACCESS) or possibly data corruption when you try to execute the block later.
When you execute a block, it's important to test first if the block is nil. Objective-c will allow you to pass nil to a block method parameter. If that block is nil, you'll get EXC_BAD_ACCESS when you try to execute it. Luckily this is easy to do. In your example, you'd write:
- (void)testWithBlock:(void (^)(NSString *))block {
NSString *testString = #"Test";
if (block) block(testString);
}
There are performance considerations in copying blocks. Compared to creating a block on the stack, copying a block to the heap is not trivial. It's not a major deal in general, but if you're using a block iteratively or using a bunch of blocks iteratively and copying them on each execution, it'll create a performance hit. So if your method - (void)testWithBlock:(void (^)(NSString *))block; were in some kind of loop, copying that block might hurt your performance if you don't need to copy it.
Another place you need to copy a block is if you intend on calling that block in itself (block recursion). This isn't all that common, but you must copy the block if you intend to do this. See my question/answer on SO here: Recursive Blocks In Objective-C.
Finally, if you're going to store a block you need to be really careful about creating retain cycles. Blocks will retain any object passed into it, and if that object is an instance variable, it will retain the instance variable's class (self). I personally love blocks and use them all the time. But there's a reason Apple doesn't use/store blocks for their UIKit classes and instead stick with either a target/action or delegate pattern. If you (the class creating the block) are retaining the class that is receiving/copying/storing the block, and in that block you reference either yourself or ANY class instance variable, you've created a retain cycle (classA -> classB -> block -> classA). This is remarkably easy to do, and it's something I've done too many times. Moreover, "Leaks" in Instruments doesn't catch it. The method to get around this is easy: simply create a temporary __weak variable (for ARC) or __block variable (non-ARC) and the block won't retain that variable. So,for example, the following would be a retain cycle if the 'object' copies/stores the block:
[object testWithBlock:^(NSString *test){
_iVar = test;
NSLog(#"[%#]", test);
}];
However, to fix this (using ARC):
__weak IVarClass *iVar = _iVar;
[object testWithBlock:^(NSString *test){
iVar = test;
NSLog(#"[%#]", test);
}];
You can also do something like this:
__weak ClassOfSelf _self = self;
[object testWithBlock:^(NSString *test){
_self->_iVar = test;
NSLog(#"[%#]", test);
}];
Note that many people don't like the above because they consider it fragile, but it is a valid way of accessing variables.
Update - The current compiler now warns if you try to directly access a variable using '->'. For this reason (as well as reasons of safety) it's best to create a property for the variables you want to access. So instead of _self->_iVar = test; you would use: _self.iVar = test;.
UPDATE (more info)
Generally, it's best to consider the method that receives the block as responsible for determining whether the block needs to be copied rather than the caller. This is because the receiving method can be the only one that knows just how long the block needs to be kept alive or if it needs to be copied. You (as the programmer) will obviously know this information when you write the call, but if you mentally consider the caller and receiver at separate objects, the caller gives the receiver the block and is done with it. Therefore, it shouldn't need to know what is done with the block after it's gone. On the flip side, it's quite possible that the caller may have already copied the block (maybe it stored the block and is now handing it off to another method) but the receiver (who also intends on storing the block) should still copy the block (even though the block as already been copied). The receiver can't know that the block has already been copied, and some blocks it receives may be copied while others may not be. Therefore the receiver should always copy a block it intends on keeping around? Make sense? This essentially is good Object Oriented Design Practices. Basically, whoever has the information is responsible for handling it.
Blocks are used extensively in Apple's GCD (Grand Central Dispatch) to easily enable multi-threading. In general, you don't need to copy a block when you dispatch it on GCD. Oddly, this is slightly counter-intuitive (if you think about it) because if you dispatch a block asynchronously, often the method the block was created in will return before the block has executed, which generally would mean the block would expire since it is a stack object. I don't think that GCD copies the block to the stack (I read that somewhere but have been unable to find it again), instead I think the life of the thread is extended by being put on another thread.
Mike Ash has extensive articles on blocks, GCD and ARC which you may find useful:
Mike Ash: Practical Blocks
Mike Ash: Objective-C Blocks vs C++0x Lambdas: Fight!
Mike Ash: Q&A - More info on Blocks
Mike Ash: Automatic Reference Counting He talks about blocks & ARC in this article.
Mike Ash: GCD Is Not Blocks, Blocks Are Not GCD
Apple Docs - Introducing Block & GCD
This all looks good. Though, you might want to double-check the block parameter:
#property id myObject;
#property (copy) void (^myBlock)(NSString *);
....
- (void)testWithBlock: (void (^)(NSString *))block
{
NSString *testString = #"Test";
if (block)
{
block(test);
myObject = Block_copy(block);
myBlock = block;
}
}
...
[object testWithBlock: ^(NSString *test)
{
NSLog(#"[%#]", test);
}];
Should be fine. And I believe that they are even trying to phase out Block_copy(), but they haven't yet.
As the blocks programming topics guide says under 'Copying Blocks':
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.
In the case you are describing, you can basically think about the block as simply being a parameter to your method, just like as if it were an int or other primitive type. When the method gets called, space on the stack will be allocated for the method parameters and so the block will live on the stack during the entire execution of your method (just like all the other parameters). When the stack frame gets popped off the top of the stack at the return of the method, the stack memory allocated to the block will be deallocated. Thus, during the execution of your method, the block is guaranteed to be alive, so there's no memory management to deal with here (in both ARC and non-ARC cases). In other words, your code is fine. You can simply call the block inside the method.
As the quoted text suggests, the only time you need to explicitly copy a block is when you want it to be accessible from outside of the scope where it was created (in your case, beyond the lifetime of the stack frame of your method). As an example, suppose you want a method that fetches some data from the web, and runs a block of code when the fetch is complete. Your method signature might look like:
- (void)getDataFromURL:(NSURL *)url completionHandler:(void(^)(void))completionHandler;
Since the data fetch happens asynchronously, you would want to keep the block around (likely in a property of your class) and then run the block once the data has been fully fetched. In this case, your implementation might look like:
#interface MyClass
#property (nonatomic, copy) void(^dataCompletion)(NSData *);
#end
#implementation MyClass
#synthesize dataCompletion = _dataCompletion;
- (void)getDataFromURL:(NSURL *)url completionHandler:(void(^)(NSData *fetchedData))completionHandler {
self.dataCompletion = completionHandler;
[self fetchDataFromURL:url];
}
- (void)fetchDataFromURL:(NSURL *)url {
// Data fetch starts here
}
- (void)finishedFetchingData:(NSData *)fetchedData {
// Called when the data is done being fetched
self.dataCompletion(fetchedData)
self.dataCompletion = nil;
}
In this example, using a property with a copy semantic will perform a Block_copy() on the block and copy it to the heap. This happens in the line self.dataCompletion = completionHandler. Thus, the block gets moved from the stack frame of the -getDataFromURL:completionHandler: method to the heap which allows it to be called later in the finishedFetchingData: method. In the latter method, the line self.dataCompletion = nil nullifies the property and sends a Block_release() to the stored block, thus deallocating it.
Using a property in this way is nice since it will essentially handle all of the block memory management for you (just make sure it's a copy (or strong) property and not simply a retain) and will work in both non-ARC and ARC cases. If instead you wanted to use a raw instance variable to store your block and were working in a non-ARC environment, you would have to call Block_copy(), Block_retain(), and Block_release() yourself in all the proper places if you wanted to keep the block around any longer than the lifetime of the method in which it's passed as a parameter. The same code above written using an ivar instead of a property would look like this:
#interface MyClass {
void(^dataCompletion)(NSData *);
}
#end
#implementation MyClass
- (void)getDataFromURL:(NSURL *)url completionHandler:(void(^)(NSData *fetchedData))completionHandler {
dataCompletion = Block_copy(completionHandler);
[self fetchDataFromURL:url];
}
- (void)fetchDataFromURL:(NSURL *)url {
// Data fetch starts here
}
- (void)finishedFetchingData:(NSData *)fetchedData {
// Called when the data is done being fetched
dataCompletion(fetchedData)
Block_release(dataCompletion);
dataCompletion = nil;
}
You know there are two kinds of blocks:
blocks stored in the stack, the ones that you explicitly write as ^{...}, and that disappear as soon as the function they are created in returns, just as regular stack variables. When you call a stack block after the function it belonged to has returned, bad things happens.
blocks in the heap, the ones that you get when you copy another block, the ones that live as long as some other object keeps a reference to them, just like regular objects.
The only reason for you to copy a block is when you are given a block that is, or may be a stack block (explicit local block ^{...}, or method argument whose origin you don't know), AND that you want to extend its life span out of the limited one of the stack blocks, AND that the compiler doesn't already do that job for you.
Think: keeping a block in an instance variable.
Adding a block in a collection such as NSArray.
Those are common examples of cases where you should copy a block when you're not sure it is already a heap block.
Note that the compiler does it for you when a block is called in another block.
Can someone explain the difference between these two, the first one is taken from allowing xcode to automatically generate the declaration, the last one is taken from an example in "Cocoa Programming" by Aaron Hillegass.
- (NSString*)planetName {
return [[planetName retain] autorelease];
}
.
- (NSString*)planetName {
return planetName;
}
I am just curious whats going on, my understanding was that the method is returning a pointer to either nil or an existing string object. I don't understand the reason for retaining and then adding to the autorelease pool?
Consider:
NSString *planetName = [myPlanet planetName];
[myPlanet setPlanetName: #"Bob"];
[planetName length];
Without [[planetName retain] autorelease], the above will very likely crash.
retain/autorelease puts the object into the current thread's autorelease pool. That effectively guarantees that the object will remain valid until the pool is drained, which is typically after the current event -- user event, timer firing, etc... -- is done processing.
(1) Use #property and #synthesize. It generates correct getter/setters for you.
(2) Read the Cocoa Memory Management guide. It answers all of these questions quite well.
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
In both cases, yes, they are both returning a pointer to either nil or the string object.
The difference is that the first code block handles memory management, the second does not. The second code block is assuming you are managing planetName somewhere else in your class instance, whereas in the first code block Apple is being as conservative as possible in keeping that memory from leaking. By putting the memory in the current autorelease pool it will be destroyed with the pool.
My recommendation would be to stick with the latter case and to be a little wiser about managing your own object instances than what XCode is auto-generating for you.