Does a NSURLConnection retain its delegate? - objective-c

Summary of my question: Does NSURLConnection retain its delegate?
Detailed question and scenario:
I have a custom class, called JsonDownloader that is takes in a URL and returns an NSDictionary of the JSON that the URL returns.
On an iPhone app, I do something like this. (the init method kicks off the whole process)
- (void)viewDidLoad {
JsonDownloder *temp = [[[JsonDownloader alloc] initWithURL:urlString returnDataTo:self]];
[temp release];
[super viewDidLoad];
}
When the JsonDownloader is done downloading and parsing, it performs a callback to the returnDataTo: object, in this case, the calling object.
This works just fine. Even if I introduce a 30 second delay in my web servers response, the JsonDownloader still exists and does it's callback correctly.
So my questions is this: What is keeping JsonDownloader way past the end of the event cycle? I am explicitly releasing it.
My hunch is that NSURLConnection must do a retain on its delegate, but I didn't see anything in the documentation. Anyone have an ideas?

There aren't many setters that don't either copy or retain a variable being passed to it, lest the memory of said variable be re-allocated to something else when its retain count reaches zero.
However, the answer is YES, it does. A little bit of test code shows the delegate's retain count go up:
NSLog(#"Retain count before: %d", [self retainCount]);
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"]];
NSURLConnection* conn = [NSURLConnection connectionWithRequest:request delegate:self];
NSLog(#"Retain count after: %d", [self retainCount]);
which produces in the log:
Running…
2009-07-09 02:13:40.516 delegateRetain[45123:a0f] Retain count before: 1
2009-07-09 02:13:40.525 delegateRetain[45123:a0f] Retain count after: 2
Debugger stopped.
So you can see pretty clearly that in connectionWithRequest:delegate: "self" is indeed having its retain count increased +1. If you're feeling brave and want to mess with the EXC_BAD_ACCESS gods, add in
[conn dealloc];
NSLog(#"Retain count after dealloc: %d", [self retainCount]);
which will print out "1" again, showing a post dealloc decrement. However, you'll get a nice Program received signal: “EXC_BAD_ACCESS”. because the NSAutoreleasePool will try to release the connection and it will be gone ;)

Most delegate properties are not retained but assigned to prevent circular references. See this question about that as well.
However, NSUrlConnection does not have a specific delegate property. You have to specify the delegate along with the initialization of the connection. I think that is why it does receive a retain, as Dave Martorana showed.

Yes, "The connection retains delegate. It releases delegate when the connection finishes loading, fails, or is canceled," according to the Xcode Documentation for -[NSURLConnection initWithRequest:delegate:] under Special Considerations. See also: NSURLConnection inherent memory leak?

Related

passing objects from no arc compiled class to arc enabled class?

I ran into this problem while trying to fix a memory leak with the facebook-ios-sdk. How do i handle this situation when passing objects from no arc compiled classe to arc enabled classe?
This is the code inside the non arc compiled Facebook library: (i removed the unnecessary stuff which is not related to the problem) as you can see, result object is not autoreleased or released.
- (void)handleResponseData:(NSData *)data {
NSError* error = nil;
id result = [self parseJsonResponse:data error:&error];
self.error = error;
// Call the defined delegate wich is my AppDelegate didLoad method wich is arc enabled
[_delegate request:self didLoad:result];
}
- (id)parseJsonResponse:(NSData *)data error:(NSError **)error {
SBJSON *jsonParser = [[SBJSON alloc] init];
//gets the object wich leaks or gets overreleased
id result = [jsonParser objectWithString:responseString];
[jsonParser release];
return result;
}
Now if i try to add autorelease to the result object, i am facing a NSZombie when my arc code in my AppDelegate try's to release the object. However if i leave the code like this i'm facing memory leaks whit the result object which gets not released.
am i missing something basic? i can't get my head around this?
Thanx for any advice! Chris
The result returned from -parseJsonResponse:... is autoreleased already (see note at bottom).
Since the name of the -parseJson method doesn't begin with new, alloc, copy or mutableCopy, the compiler assumes that it returns an object with a +0 reference count, meaning it needs to be retained by the calling code if it is to be kept around, and doesn't need to be released if it's not being kept around. That's a long winded way of saying that it should neither leak nor cause a crash in your ARC code as written in your question.
Passing objects between ARC code and manual reference counting code doesn't require any special handling. You just need to make sure that methods' names match their memory management semantics in the non-ARC code. It certainly seems like you've done that in this case, although as you say, you didn't post your complete code.
Note: Presumably, objectWithString: returns an autoreleased object. If it doesn't it, it should (because it doesn't start with alloc, new, copy, mutableCopy).

What is meant by [self release] in Objective-C? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is calling [self release] allowed to control object lifetime?
What will happen if I use this code snippet?
[self release]
self descrements its own retain count by one, just like release would do with any other object.
The only situation however that I have so far come across, where such a call was appropriate, was the case where an init… method would fail and be expected to return nil and deallocate the just allocated instance.
In 9 out of 10 situations you shouldn't use [self release], I'd estimate.
Something like this (which basically forbids the calling of - (id)init;, for cases where you want to force the use of a particular - (id)initWith… method.):
- (id)init {
[self release];
NSString *reason = [NSString stringWithFormat:#"%# is not a valid initializer for the class %#", NSStringFromSelector(_cmd), NSStringFromClass([self class])];
#throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:reason
userInfo:nil];
return nil;
}
or this (which basically enforces the proving of an object on initialization)
- (id)initWithFoo:(Foo *)foo {
if (!foo) {//foo is required to be non-nil!
[self release];
return nil;
}
//proceed with initialization
return self;
}
These however are not the only ever occasions where [self release] would be appropriate. But merely the ones I've come across so far. (as Oliver correctly pointed out)
Edit: Self-invalidating NSTimers would probably be another (quite common, yet somewhat special) situation.
You will release yourself, what means that the object declares itself that it does not have to still live. If no one else retains tha object, it dies and its memory is freed
You have little reasons to do that, except if you want to create object that are not controlled by anyone else and are self controlled.
I mean, for example, there is the case where you may want to create an self living object that makes some treatments, and suicide when it has finished without having to tell anyone else it has finished.
Let's imagine for example a class whose purpose is just to send a message to a server :
You instanciate the class, as soon as it is istanciated it send a message to a server, it waits for the server answer, and if the answer is ok, it suicide. That way, you don't have to manage any server answer from within another class controller whose purpose is not to manage such events.
It just decrements the receiver’s reference count.

Setting object to nil after release -- TT_RELEASE_SAFELY

I have started to study Three20 and I have a simple question about TT_RELEASE_SAFELY
Up till now I like to write code in this way:
UILabel *lab = [[UILabel alloc] initWithFrame:rect];
[self.view addSubview:lab];
[lab release];
Here I think the main pool is responsible to free the memory of lab.
Now I have found TT_RELEASE_SAFELY which is defined like so:
#define TT_RELEASE_SAFELY(__POINTER) { [__POINTER release]; __POINTER = nil; }
As you can see, after release, it sets the object to nil.
I'd like to know the difference between the two ways and which way is better.
Thanks.
Sending a message to nil is valid in Objective-C. Sending a message to a deallocated object is not.
Sending a message to a deallocated object:
id obj = [[MyClass alloc] init];
[obj release];
[obj doSomething]; // Crash!
Sending a message to nil:
id obj = [[MyClass alloc] init];
[obj release], obj = nil;
[obj doSomething]; // Valid
Assigning nil to a variable after an object has been deallocated is controversial because it can prevent you from realizing that something is wrong. Sedate Alien's example:
[controlCenter dealloc];
...
float timeLeft = [controlCenter timeToWaitBeforeBombDetonation];
This code will crash since controlCenter has been deallocated. As a result this defect will be detected and fixed early.
[controlCenter dealloc], controlCenter = nil;
...
float timeLeft = [controlCenter timeToWaitBeforeBombDetonation];
This code will assign 0.0 to timeLeft which appears to be a valid wait time even though controlCenter is nil.
Take the above with a grain of salt, since if you are writing an Objective-C app, you are probably more concerned with keeping your users happy by avoiding crashes than destroying cities. If the latter is a concern, you should probably be using a type-safe language like Ada.
I believe that using these variants of "safe releases" is an expressly bad idea.
Your application will fail in silent and mysterious ways, as messages passed to nil will not raise any warnings. It's much better to not nil out your references and take advantage of all that NSZombieEnabled has to offer.
The only difference is that TT_RELEASE_SAFELY sets the pointer to nil after release, so the reference won't be used after release. The pattern is a good one to follow and the TT_RELEASE_SAFELY macro makes it simpler to implement.

Random BAD_ACCESS and "not recognized selector"

Hey, I'm a beginner in Objective C, and my .NET and Java years have rusted my memory management skills, so it's very likely I'm missing something here.
I am building an iPad app. The main view is a SplitView with a TableView on the left, and the detail view contains another TableView. The loading of the latter with data has been commented out in an attempt to single out my problem.
The app seems to work fine (has to fetch data from a .NET WS and parse it into the table), but at random times I receive a BAD_ACCESS or a "selector not recognized" errors.
The selector not recognized error I get here:
-(void) connection:(NSURLConnection *) connection
didReceiveResponse:(NSURLResponse *) response {
[webData setLength: 0];
}
This piece of code I'm sure most of you know about, I got it from all samples I found online and in books to send a web request.
Beats me why it says it does not recognize the setLength selector, webData is defined as
NSMutableData *webData;
Any ideas?
Thanks.
If you do not allocate your webData object either with
NSMutableData* webData = [[NSMutableData alloc] initWithCapacity:2048];
or
NSMutableData* webData = [[NSMutableData data] retain];
then the webData object will most likely be autoreleased during one of the context switches from the NSURLConnection message that you allocated it in (probably connection:didReceiveData:) to the connection:didReceiveResponse: message.
Any object that you do not alloc or explicitly retain is likely to be deallocated during scope changes, even if it is a member variable of your class.
Most likely you aren't creating the NSMutableData correctly. I expect you have code that looks like
webData = [NSMutableData data];
This is going to give you an autoreleased object, and yet you're storing it in an ivar. You need to take ownership of the object when storing it in an ivar. In your case, the simplest way is just to skip the convenience method and go with alloc/init:
webData = [[NSMutableData alloc] init];
For more details, read the Memory Management Programming Guide.
Seems to be very usual (not only beginners) error, when connection is not cancels in dealloc or viewWillDisappear. When you are leaving the controller, you should cancel all connection, timers, etc, created by the controller, to prevent them from calling delegate methods or selectors on deallocated controller objects.
It looks like webData is being deallocated and replaced with some other object. Make sure you retain it if you don't use alloc/init or mutableCopy to get it.

ObjC delegate methods never gets called

I am creating instances of a class FlickrImage parsing a Flickr API photos response. The class has a method getLocation that does another API call to get the geolocation:
NSLog(#"getting location for %i",self.ID);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
OFFlickrAPIRequest *flickrAPIRequest = [[OFFlickrAPIRequest alloc] initWithAPIContext[appDelegate sharedDelegate].flickrAPIContext];
[flickrAPIRequest setDelegate:self];
NSString *flickrAPIMethodToCall = #"flickr.photos.geo.getLocation";
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,#"api_key",self.ID,#"photo_id",nil];
[flickrAPIRequest callAPIMethodWithGET:flickrAPIMethodToCall arguments:requestArguments];
[pool release];
I have implemented the callback method that would catch the response from the API and update the FlickrImage instance with the geolocation data - but it never gets called. Here's where the instances get created:
NSDictionary *photosDictionary = [inResponseDictionary valueForKeyPath:#"photos.photo"];
NSDictionary *photoDictionary;
FlickrImage *flickrImage;
for (photoDictionary in photosDictionary) {
flickrImage = [[FlickrImage alloc] init];
flickrImage.thumbnailURL = [[appDelegate sharedDelegate].flickrAPIContext photoSourceURLFromDictionary:photoDictionary size:OFFlickrThumbnailSize];
flickrImage.hasLocation = TRUE; // TODO this is actually to be determined...
flickrImage.ID = [NSString stringWithFormat:#"%#",[photoDictionary valueForKeyPath:#"id"]];
flickrImage.owner = [photoDictionary valueForKeyPath:#"owner"];
flickrImage.title = [photoDictionary valueForKeyPath:#"title"];
[self.flickrImages addObject:[flickrImage retain]];
[flickrImage release];
[photoDictionary release];
}
The retain is there because I thought it might help solve this but it doesn't - and doesn't the NSMutableArray (flickrImages is a NSMutableArray) retain its members anyway?
EDIT I should add that the getLocation method (first code snippet) is launched in a thread:
[NSThread detachNewThreadSelector:#selector(getLocation) toTarget:self withObject:nil];
Your delegate method is never being called because the request is never being made. When you call callAPIMethodWithGET:, it sets up communications to run asynchronously on the current thread's run loop, then returns immediately. That way you can safely call it on the main thread without blocking.
Because you are calling the method from a thread you created yourself, it does not see the main run loop, but the run loop for your new thread. However, because you never execute the run loop, the messages are never sent, a response is never received, and your delegate is never called.
You could fix this by calling [[NSRunLoop currentRunLoop] run] in your new thread. That will let the work happen. But in this case would be easier to never detach a new thread in the first place. Your program won't block, and you won't have to worry about your delegate method needing to be reentrant.
I've also run into this problem when requesting and parsing XML on a different thread my solution was to do this:
while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:start] && !isFinished){
}
Where start = [NSDate dateWithTimeIntervalSinceNow:3]; this is basically a timeout so that it doesn't live forever and isFinished is set to true when my parsing has completed.
I'm not familiar with these flicker API wrappers, but in this code:
NSDictionary *requestArguments = [[NSDictionary alloc] initWithObjectsAndKeys:FLICKR_API_KEY,#"api_key",self.ID,#"photo_id",nil];
Are you certain that both FLICKR_API_KEY, and self.ID are not nil? If either of them is nil, you'll end up with a dictionary that has less items in it than you intend.
Could you post the callback method(s) you have implemented – this could be just down to a simple typo, as it appears OFFlickrAPIRequest won’t do anything if the delegate does not implement the required callback.
Did you also implement flickrAPIRequest:didFailWithError: to see if there was an error returned from the API call?
Okay, I did solve it, with help from some of the suggestions above.
I did remove the extra retain because it did in fact create a memory leak. It did not look right from the outset, so my gut feeling about that is worth something, which is a good thing ;)
I removed the redundant threading because the API call is already asynchronous and does not require an additional thread to be non-blocking. After that, the callback method was being called but I ran into different problems concerning object retention. If interested you might want to check out that question, too
Thanks all.
The setDelegate method of OFFlickrAPIRequest does not retain the delegate like it should. This means you're stuck ensuring that your delegate is alive as long as the request is (or patching the class to properly own its own references).