Can I create an NSURLConnection object with an asynchronous request in applicationDidFinishLaunching:, and not keep a reference to it in an instance variable, as follows?
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSURLConnection *localVariable = [[NSURLConnection alloc] initWithRequest:req delegate:self];
}
I believe this should work when not using ARC. While I no longer have any reference to the NSURLConnection object, it should do its job and not get deallocated until I release it in one of its delegate methods, like connectionDidFinishLoading:, because it leaves applicationDidFinishLaunching: with a retain count of +1, right?
The question, however, is: Is this considered bad style? Should I always maintain an instance variable with this kind of object relationship? What would I do to make this work with ARC? After all, when localVariable goes out of scope, ARC would deallocate my NSURLConnection, I suppose.
I could not find an official reference for this, but it seems that an NSURLConnection created with initWithRequest keeps a strong reference to itself, to prevent it from being deallocated. This reference is deleted only after the final delegate function has been called, or the connection has been canceled.
(See e.g. been having a little confusion about the retainCount of NSURLConnection or http://www.cocoabuilder.com/archive/cocoa/110116-nsurlconnection-retaincount-at-initialisation.html)
Therefore your code works also with ARC: Even when localVariable goes out of scope, there is another reference to the connection as long as the connection is "active".
This means that you don't have to keep a reference to the connection. But it is useful because it enables you to cancel the connection if necessary.
Related
Is there ever a case where purposely creating a retain cycle to prevent deallocation, then cleaning it up later, is the best solution to a problem?
If so, are there examples of this in the Cocoa Touch or NextStep frameworks?
I intend this question to be specific to Objective C with ARC since Objective C with GC or other languages with GC may behave differently.
Sure. It's actually not all that uncommon, though you may not realize it.
For example, let's assume that my controller is making a network request, and I really need to make sure I handle the response, even if the user has navigated away from that controller.
I might do something like this:
- (void)doNetworkThing {
__block MyController *blockSelf = self;
NSURLRequest *request = // some request
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error) {
// Handle the response here
[blockSelf doThingWithResponse:response];
}];
}
This introduces a trivial retain cycle where self has caused itself to be retained by assigning itself to the strong pointer blockSelf. Until blockSelf goes out of scope, self will not be deallocated.
Note that often, you would use a weak pointer in this situation. But if you really need the controller to be around to handle it, using a strong pointer works too. As soon as the handler block is deallocated, its reference to blockSelf will go away. Since the the stack reference to blockSelf is also gone self will then be deallocated if nobody else is holding on to it.
So basically, blockSelf caused a temporary retain cycle, which was useful in ensuring that deallocation could not happen until the request finished. Because ARC automatically cleans up the retain counts when the __block variable goes out of scope, it doesn't look much like a retain cycle. But nevertheless, that's what it is.
Sure, there are several. Most notably NSURLConnection generates a retain loop with its delegate to ensure that the delegate cannot go away before the connection completes. Somewhat less ideally, NSTimer generates a retain loop with its target. This unfortunately causes problems for repeating timers (see RNTimer for one of many attempts to work around this issue).
Generally speaking, if a delegating object has a very short lifespan compared to its delegate, it is natural for it to retain its delegate in order to create a beneficial retain loop.
It is much less common, but still done, for certain kinds of objects to "self retain." For example, if you had an object that you wanted to create and have some operation perform, and then destroy itself, then self retain can solve that problem. Typically it is better to avoid that and let the caller retain the object, but it still has its uses (I've used it for logging and other non-critical operations that I want to fire-and-forget).
That said, it is not uncommon in my code to intentionally create short-lived retain loops with blocks to ensure that the calling object cannot vanish before the block finishes.
After transitioning a project to ARC, I've been having some issues with delegate methods not being called/being called on deallocated instances. I've realized that the problem is that I have a variable that gets allocated and then executes an asynchronous task. For a simple example, assume that there is an object called MyService that responds to a delegate method, executeDidSucceed:
- (void)fireRequest {
MyService *service = [[MyService alloc] initWithDelegate:self];
[service execute];
}
The original code would look something like this:
- (void)fireRequest {
MyService *service = [[[MyService alloc] initWithDelegate:self] autorelease];
[service execute];
}
With ARC, I understand that a release call gets added after [service execute] gets called. And I also understand that because the method is asynchronous, the service object will get deallocated, and a call to the deallocated object will be made for the delegate method.
I know a solution would be to make service an instance variable and give it the strong property so we can retain ownership of it. And I know of a solution where we could create a block and use a completion handler so the delegate stays retained until the block is completed. My question is, what's the best way of handling a situation like this? Or more so, what's the "best practice" for resolving this while transitioning to ARC?
You will need to make your Myservice object a member to this class. ARC is cleaning it up as soon as this function completes because you no longer have a reference to it.
It's also my opinion that its a good practice to do since you don't have a reference to that object until it calls a delegate (if it does) and depending on the situation you may need stop the service before it completes.
I've got a class which uses NSURLConnection to open a long-running connection to a server. When the connection's closed, either in connectionDidFinishLoading: or connection:didFailWithError:, I want to wait 15 seconds then retry the connection.
At the moment I'm using [self performSelector:#selector(restartConection) withObject:nil afterDelay:15.0];, but this leads to the undesired situation that when the object is released by its creator, the performSelector and NSURLConnections perpetually retain 'self', and it never gets deallocated.
How can I do this without perpetually retaining the object? Any help'd be much appreciated.
Thanks, -Alec
I think your only option is to send
[NSTimer cancelPreviousPerformRequestsWithTarget: object];
at some point, probably, before releasing the object. If the timer hasn't been scheduled, this is a no-op, but is not free performance-wise.
You cannot avoid retaining the object. It is retained in order to save you from ugly crashes when in the next main loop cycle the runtime is going to call your selector on the released object.
If you really insist on having your object released immediately without waiting for your delayed selector, I would suggest you to create a separate proxy class. Say your class is called A, create proxy class B which will have a weak reference to your class A (i.e. __weak A* a) and restartConnection selector which will check if the weak reference is valid. If so it would invoke restartConnection on your A object. Then, do, of course, a delayed selector on B's restartConnection
But first of all, I would really suggest that you reevaluate whether you really cannot live with the retain.
I'm so very sorry for the unclear title, but I can't explain it shortly.
I am basically wondering what happens if you use ARC and you have a method like this:
- (void)fooMethod:(NSURLRequest *)fooReq
{
NSURLConnection *fooConn = [NSURLConnection connectionWithRequest:fooReq delegate:self];
[fooConn start];
}
So fooConn goes out of scope at the end of the fooMethod, but will I still receive callbacks? In other words: because there aren't any more references, will it get dealloc'd (or something like that) immediately, or will it stay in memory and handle the request because the delegate is still set?
That totally depends on what NSURLConnection does behind the scenes. If the retain count drops to zero, then fooConn will be dealloc'ed still and one would assume no more callbacks would be made then.
Now, I think that NSURLConnection behind the scenes does get retained somewhere in the hierarchy of things so you would in fact receive callbacks. However with NSURLConnection I usually keep a strong reference to it lying around to be on the safe side. After all, you as the caller of it want to own it and you want to ensure that you will keep getting the delegate callbacks and not be at the mercy of whatever happens to it under the hood.
So, in short, if I were you I'd keep a strong reference to it to ensure you won't have to worry.
From the Apple docs:
- (id)initWithRequest:(NSURLRequest *)request delegate:(id < NSURLConnectionDelegate >)delegate startImmediately:(BOOL)startImmediately
The connection retains delegate. It releases delegate when the connection finishes loading, fails
fooConn is a local variable without any ownership qualifier so ARC will infer it as strong. Therefore ARC will retain the value returned by connectionWithRequest:delegate: when storing it into foxConn; and when exiting fooMethod: ARC will clean up by releasing fooConn.
That the delegate references the current instance will have no effect on this.
If you wish the NSURLConnection to exist after fooMethod: returns one way is to store it into an instance variable (which ARC also infers as strong, so no ownership qualifier required there either). If you do this when the class instance itself is no longer reference ARC will release the NSURLConnection.
I have a method of an object which creates objects which are then passed to a method of another object in another thread, like this:
MyClass* myClass = [[MyClass alloc] init];
[anotherClass performSelectorOnMainThread:#selector(method) withObject:myClass waitUntilDone:NO];
in method, I immediately retain the object, supposing it will be somehow released by the creator. My question is: how do I make MyClass release that object correctly? Is this the correct way to go?
My solution was to release the object manually in method. I see anyway that the Leak analyzer still recognizes this as a leak and seems it is not what Apple recommends, as the owner has the responsability to release the object.
Can you explain me the correct way to handle this situation? Thanks!
I don't fully understand what you're trying to achieve, but in general:
You shouldn't worry about who and when releases/deallocates the object. Instead, just make sure to retain it when you (a single object or method of yours) start needing it and release it when you stop needing it (or autorelease it, in which case it will be released on the thread on which you called autorelease).
This is exactly the way the performSelectorOnMainThread:withObject:waitUntilDone: works. From the documentation:
This method retains the receiver and the arg parameter until after the selector is performed.
It retains them while it needs them for doing it's job.
In short, the mehod that creates the objects and sends them to another thread should be:
MyClass* myClass = [[MyClass alloc] init]; // retained, will need it for performSelector
[anotherClass performSelectorOnMainThread:#selector(method) withObject:myClass waitUntilDone:NO];
[myClass release]; // no longer needing it.
or
MyClass* myClass = [[[MyClass alloc] init] autorelease]; // will be released automatically, but guaranteed to be retained until this method returns
[anotherClass performSelectorOnMainThread:#selector(method) withObject:myClass waitUntilDone:NO];
The way you have it now is a memory leak.
The receiving method:
if it uses the object only internally, doesn't have to retain it, since performSelector does "until after it is performed" (the method returns).
if it needs it later, it should be assigned to a property which retains it.
Your question is very hard to understand because you talk about this object, that object, another object and use meaningless names like myClass, anotherClass and method. It remains unclear which object you intend to release and which one is reported as leaking.
Anyhow, multi-threading doesn't add any special complexity to reference counting. Certainly, your two object myClass and anotherClass aren't short-lived objects. So if you use autorelease, make sure that the reference counter doesn't go to 0 if all autoreleases have been executed.
It's perfectly okay to release either myClass or anotherClass or both in method.
You don't show a lot of code. But what you show is okay.