Should I release the NSThread I create? - objective-c

I'm probably overthinking this.
// Inside some method...
NSThread *thread = [[NSThread alloc] initWithTarget:functionWrapper selector:#selector(run) object:nil];
[thread start];
Calling [thread release] after this: A. Avoids a memory leak and is necessary or... B. Will break things.
The answer to this question suggests that the thread will release itself when it finished executing, but where is that behavior documented?

Yes you will have to release it some time later, either through autorelease or release.
However, you don't really need to init your own thread in the first place, objective-c has plenty of ways for you to implement threading without allocing a new thread yourself, like
[self performSelectorInBackground:#selector(yourMethod) withObject:nil];
There are also NSOperations that allow you to queue up your tasks as well.

As a general rule: If you call alloc, new, or copy on an object, you have to release it.
Once the lifecycle of that thread is complete (or in your dealloc function), call [thread release].
The difference with the answer you linked to, you'll see he had autorelease at the end of the string (autoreleasing is the instance where the rule above doesn't apply, in those cases the object will be automatically released at the end of the current main run loop so that it is alive for the entire current scope).

Related

Is dealloc guaranteed to be called on the same thread that created the object?

Is dealloc guaranteed to be called on the same thread that created a NSObject instance? For example, if I call [[MyFluffyBunny alloc] init] on the main thread, is dealloc guaranteed to also be called on the main thread, or can it be called on any thread once MyFluffyBunny is no longer retained?
I see sporadic crashes in my app that points to that it's not guaranteed, but I've been unable to find any documentation confirming it.
The object is deallocated on whatever thread releases the last strong reference to it. That is, whatever thread calls -release the final time. It is actually during that -release call that the object is deallocated.
The documentation for the -release method in the NSObject protocol says:
Decrements the receiver’s reference count. … The receiver is sent a dealloc message when its reference count reaches 0.
The Advanced Memory Management Programming Guide: Practical Memory Management article includes this among the reasons to not use -dealloc to manage scarce resources:
Cleanup logic being executed on the wrong thread.
If an object is autoreleased at an unexpected time, it will be deallocated on whatever thread’s autorelease pool block it happens to be in. This can easily be fatal for resources that should only be touched from one thread.
There is no such guarantee and, in fact, it makes for some subtle bugs when using KVO (and bindings on OS X).
You can see it in action fairly easily by creating an object that logs [NSThread currentThread] during init and dealloc, then running code such as:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Testing *testing = [[Testing alloc] init];
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), ^{
NSLog(#"Use testing in background: %#", testing);
});
testing = nil;
return YES;
}
I'm unaware of a line in the documentation that says anything about this, but here are some points of logic:
If you can't find a guarantee somewhere, assume it doesn't exist. (It sounds like you're aware of this already, and are hoping beyond hope that somebody else can point you to something that gives you the answer you want)
That requirement cannot be possible because you can construct something on a thread, then end that thread, then have the last reference go out of scope somewhere else in some other thread. It wouldn't be possible at this point to dealloc on the old thread because it no longer exists.

Does detachNewThreadSelector work any different than NSThread performSelectorInBackground or NSThread alloc/init then [thread start]

Does detachNewThreadSelector work any different than performSelectorInBackground? In my project I use a lot of this:
[self performSelectorInBackground:#selector(startImageDownloads:) withObject:[NSNumber numberWithInt:dataType]];
but would doing this be any different:
[NSThread detachNewThreadSelector:#selector(startImageDownloads:) toTarget:self withObject:[NSNumber numberWithInt:dataType]];
And also, besides being able to access the thread object with imgDlThread, would alloc/init'ing a thread then starting it work any different then the first 2:
NSThread *imgDlThread = [[NSThread alloc] initWithTarget:self selector:#selector(startImageDownloads:) object:[NSNumber numberWithInt:dataType]];
[imgDlThread start];
Thanks!
Edit:
Just realized there's several answers on SO already for the difference (or lack of) between performSelectorInBackground and detachNewThreadSelector, so I guess my only question is:
Is allocating and initializing a NSThread then calling [thread start] any different then the first 2?
The only difference between the third method and the first two is memory management. When you allocate a thread, it retains it's target, only to be released when the thread is deallocated. The detatchNewThreadSelector: and performSelectorInBackground: method both autorelease the resulting NSThread that is created, meaning that, once the thread finishes execution, the target will be released.
In the code that you provided (allocate a thread and start it), you are leaking imgDlThread, meaning that target will never be released, and in turn will be leaked itself. If you autorelease or even regular release imgDlThread after starting it, it will have the exact same effect as detachNewThreadSelector:.

after self released

I'm using a third-party Objective-C library that makes a web request in a background thread, then returns the result by using [self performSelectorOnMainThread:...] which then calls a delegate method. I understand that I need to nil the delegate reference before releasing the delegate, but I was wondering what happens if this requesting object itself gets deallocated while the background thread is running. Will this internal self reference get set to nil so that the -performSelectorOnMainThread: call is harmless, or is there a potential for a crash here?
As far as I understand your scenario (but possibly you should include some code), the statement:
[self performSelectorOnMainThread:...]
should be the last one to be executed in your thread (since it is the way to return the result of your thread, it is still part of the thread selector passed to NSThread).
If it is reasonably so, then consider that when you first detach an NSThread, you pass it a target object (your self) and the NSThread will retain it as long as the passed selector hasn't completed. This will include your [self performSelectorOnMainThread:...], so, unless someone messes heavily with releases, there should be no chance for self to be deallocated before [self performSelectorOnMainThread:...] is executed.
If your question was exactly what happens if someone messes with releases, I will give this a second thought.
If your object is deallocated before the method on the main thread completes, you have a memory management problem. The performSelectorOnMainThread:… family of methods cause the receiver to be retained until it has done its work, so the only way it could be deallocated is if you're over-releasing the object.

Objective C: Memory management in Block cases

I am wondering if I am using blocks as shown in the code below
__block Loader *loader = [[Loader alloc]initWithResourcePath:self.resourcePath];
[loader setCompletionHandler:^(NSArray *anArray){
self.answerArray=anArray;
[self reloadData];
}];
[loader getObjects];
My question is with regards to memory management. The analyzer tells me that there is a potential leak (since I did an alloc/init for my loader). How can I stop the leak here? I tried to release the loader at the end but that causes my app to stop functioning. Any advise is appreciated here
Several issues:
there is no reason for loader to be declared __block; you aren't re-assigning in the block and, thus, the __block is pointless.
the leak is because you alloc/init the loader, but never release it
do not name methods getSomething; the get prefix is reserved for methods that return stuff by reference. Just call it objects. If it is supposed to trigger the load, then call it load or performLoad.
If it is asynchronous, then getObjects is pointless. If synchronous, then the completion block is pointless.
If loader is to be used synchronously, release it at the end of the method. If it is asynchronous, then the completion block could release it. Note that the use of __block in this case is still pointless; while referring to loader in the completion block will create a retain cycle, it will be broken when you explicitly Block_release() the block in your loader (because you must have done a Block_copy() when setting the completion handler if it is to be used asynchronously in the first place).
If you plan to use loader outside of the function calling your block, it is highly possible that you need to store it in a ivar of your controller (I guess, it is a controller, but I don't know what kind of class owns the code you shows). Once you do that, you can release it in your dealloc.
The reasoning is that loader should live across several methods and runloop cycles, so a local variable will not do.
Otherwise, just release it at the end of the block, once you have done with it.
If this does not seem right to you, then possibly more code is needed.
I'm going to make some assumptions: 1) The completion handler (block) is used by method getObjects. 2) getObjects is asynchronous (it returns to the caller right away though it continues to process).
With these assumptions you can't send release after sending getObjects because getObjects is still using the completion handler.
Try sending a release or autorelease at the end of the completion handler. That should free loader provided reloadData is not also asynchronous.

Is it dangerous to set off an autoreleased NSOperationQueue?

I have a task that takes a rather long time and should run in the background. According to the documentation, this can be done using an NSOperationQueue. However, I do not want to keep a class-global copy of the NSOperationQueue since I really only use it for that one task. Hence, I just set it to autorelease and hope that it won't get released before the task is done. It works.
like this:
NSInvocationOperation *theTask = [NSInvocationOperation alloc];
theTask = [theTask initWithTarget:self
selector:#selector(doTask:)
object:nil];
NSOperationQueue *operationQueue = [[NSOperationQueue new] autorelease];
[operationQueue addOperation:theTask];
[theTask release];
I am kind of worried, though. Is this guaranteed to work? Or might operationQueue get deallocated at some point and take theTask with it?
There's nothing in the documentation to say what happens when the NSOperationQueue is released. It would be safest to assume there's no guarantee that theTask will get executed.
I would have guessed that an NSOperationQueue releases its tasks when it's released, but I've noticed that the tasks do complete and dealloc even if I release the queue immediately after adding the task. That said, I don't think I'd rely on that behavior - there's more to gain by storing the NSOperationQueue in an instance variable (and releasing it in dealloc). An instance variable will give you a way to call other methods on the queue (cancelAllOperations, setSuspended, etc).
Can't you use the [NSOperation mainQueue] object so that you don't need to worry about autoreleasing it? If you only need to add one task that seems to make the most sense to me.
http://developer.apple.com/mac/library/documentation/Cocoa/Reference/NSOperationQueue_class/Reference/Reference.html#//apple_ref/doc/uid/TP40004592-RH2-SW21
There's no guarantee that it's safe to release an NSOperationQueue while it's still working. I suspect it probably is safe and this guarantee will probably be added someday, but it isn't there now. However, the equivalent Grand Central Dispatch API does guarantee that you can safely release its queues when you're done using them and it will keep them around as long as it needs them. So if you're on a platform with GCD, you can use that to be sure it won't blow up in the meantime.
Alternatively, you could create a wrapper class that checks if a queue is finished and releases both the queue and itself when the queue is finished.