Variable released prematurely during asynchronous request - iphone

My memory-management and threading knowledge is very limited, so I may be missing something really basic. I've found a work-around for this problem, but it really, really bothers me that I can't see what's happening.
I have a class that makes two asynchronous HTTP requests, one for an XML configuration file and another for an image. Because there are two asynchronous requests going on in the same class, I'm reusing the same NSURLConnectionDelegate methods (maybe factor). I first asynchronously fetch the configuration file and extract two urls, stored as sponsorImage and sponsorUrl. Then I use the value of sponsorImage to asynchronously fetch image data. I've found, though, that after I've got my image (after the second asynchronous event has completed), sponsorUrl has been released.
I accidentally found that I can prevent sponsorUrl from getting released if I "do something to it" in the method where the image request is created -- and by "do something", I mean just that. Basically, my code looks like this:
- (void) loadImage
{
sponsorUrl = [sponsorUrl stringByAppendingString:#""];
NSURL *url = [NSURL URLWithString:sponsorImage];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:dateString forHTTPHeaderField:#"If-Modified-Since"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
[connection release];
}
If I remove the first line of this method (where I'm adding "" to the url), the variable is retained. If I remove it, it gets released. This makes no sense to me at all.
I've tried declaring sponsorUrl with #propterty (nonatomic, retain); I've tried declaring sponsorUrl statically; I've tried adding [sponsorUrl retain] where I set it, but it doesn't make a difference. The only thing that works is "touching" the variable before making the second request.
What am I missing?

As your are using a convenience constructor the variable is autoreleased! Only if you are using methods like alloc, copy or new they are retained implicitly.
Secondly, by writing sponsorUrl = .... your are not using the generated setter but the generated instance variable. You will need to write self.sponsorUrl = #"Blah"; or [self setSponsorUrl:#"blah"] in order to have the setter retain the variable.

Indeed, it seems you have some issues with memory management.
It is pretty difficult to explain what is happening because you are not providing the full code that uses your variables. Just as an example, take the statement:
sponsorUrl = [sponsorUrl stringByAppendingString:#""];
what you do is assigning to sponsorURL a new value; the old value (the one you initialized the variable with in the first place, i.e., the one that got the retain you mention) is released (stringByAppendingString forges a new object); the new object that sponsorURL points to is an autoreleased object whose lifetime is not exactly known: we only know that at some point it will be freed (possibly at the next main loop iteration). So, by "touching" the variable, you are assigning a new value to it which has a lifetime starting with the point where you touch the variable... pretty unreliable, in any case.
My suggestion is the following:
define two properties in your class to handle sponsorURL and sponsorImage;
make them of the retain kind;
assign value to them only through their accessor methods, i.e, self.sponsorURL = [...]
make sure that any objects you assign to the properties are autoreleased objects (or else, do a release with the assignment).
If you provide more code, then it would be possible to review it more thoroughly, but if you follow the guidelines above, you will have no problems at all (approx...)

Related

Why does using __weak not cause local variable to nil out immediately?

I've been working on the same project for some time now, and my understanding of Objective-C and Cocoa has evolved a little through time. Looking back in some parts of my code, I see this:
__weak ASIFormDataRequest *serverQueueRequest = [ASIFormDataRequest requestWithURL:url2];
[serverQueueRequest setCompletionBlock:^{
NSLog(#"%#", serverQueueRequest.responseString);
}];
[serverQueueRequest startAsynchronous];
And that's how I've been processing all my server requests. I think I did that to suppress a warning, namely that "capturing request in block may lead to a retain cycle". So I made it weak, and that seems to have solved all my issues. I haven't noticed any real problems with this.
However, looking at the code now, it seems a little odd that it works. When I declare the request as __weak, shouldn't it immediately zero out since no one is holding on to it? Why does this code work?
Also, although this code works, I just recently discovered a case where it doesn't: when calling the method that contains this code several times in succession, say 5 times within the span of a second, 3/5 requests will have a NULL response. This is consistently the case. Removing the __weak qualifier solves this issue. What's the explanation for that?
And so finally, what is the correct way to declare a local request like this?
Update: According to this question, the correct way to do it is like so:
ASIHTTPRequest *_request = [[ASIHTTPRequest alloc] initWithURL:...
__weak ASIHTTPRequest *request = _request;
Edit: actually the fix above does not fix the issue where calling the code 5 times results in NULL responses. That problem still exists. The only way that problem goes away is by capturing the request strongly and not using any qualifiers.
Now the question is why my original code still worked..
Quoting from Apple's Programming with ARC Release Notes:
Take care when using __weak variables on the stack. Consider the
following example:
NSString __weak *string = [[NSString alloc] initWithFormat:#"First Name: %#", [self firstName]];
NSLog(#"string:%#", string);
Although string is used after the initial assignment,
there is no other strong reference to the string object at the time of
assignment; it is therefore immediately deallocated. The log statement
shows that string has a null value.
The obj C stack will always retain pointers in scope. _weak does not mean release right now it means release when the stack goes out of scope.
When you declare a var and then make calls on it in the same stack scope it will not be released until after (minimally) the stack is cleaned up.
Blocks extend method scope since they imply potentially asynchronous behavior and they utilize the stack that was present when they were invoked.
I believe it is because you are running the weak variable in a block. The block holds onto the state of the weak variable which In turn causes it to work. I'm betting much work on the variable once the block is complete may cause issues.
My guess in why it fails if you run it many times is because the asynchronous asi call stack gets to high and bombs. I've seen this before and if you are very patient you can catch the asi blow up in the debugger.

iPhone NSURLConnection initialization problem

What is difference between this two lines, they are in different apps but first one seems to work and I have problems with the second one; and which one should i choose over another? my app will constantly receive and send back data with a webservice.
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
NSURLConnection *theConnection = [NSURLConnection connectionWithRequest:request delegate:self];
And where should I release the connection object, after every didFinishLoading? but then doesn't it take much time on every request to connect?
The first one is an instance of NSURLConnection where you take ownership of the object, so you have the responsibility and hence must release it. Details on ownership reference.
The second one is an auto-released object so you dont need to release it. It will be released automatically when the auto-release pool is drained.
The second creates an auto-released connection, so if you don't explicitly retain it, it will disappear and your application will probably crash.
You can use either, you just need to understand objective-c memory management on the iPhone.
There is, as ever, a good explanation on the Apple site, it really is worth reading and understanding as once the penny drops, you'll never make the same mistake again.
with first line you create an object with init method , which make you the owner of the object , so you must release it . The second line you use a convenient constructor, which does not make you owner of that object.in this case, if you want to manipulate with life-cycle of that object you must send another message to retain it : NSURLConnection *theConnection = [[NSURLConnection connectionWithRequest:request delegate:self] retain], and the count of object will be 2 .. even if in the second line your object automatically receive a autorelease message , the count after that will be 1 .. so if you retain object you must release it ...
you asked : And where should I release the connection object ? i think in method called connectionDidFinishLoading:connection or in the method connection:didFailWithError:

About using convenient method and the time of their autorelease

This maybe too basic but I couldn't find an exact answer. I'll be happy to delete/close this post if anyone point me to similar posts.
I want to call method "getString" to return a formatted string and set to my label like this:
-(NSString*) getString {
NSString *result = [NSString stringWithFormat:#"blah blah %#", someOtherString];
return result;
}
-(void) viewDidLoad {
someLabel.text = [self getString];
}
This code worked for me, but I am concerned that result is allocated by a convenient method thus may be auto-released before it got retained by the label. Is it true? If so, when exactly would an object from convenient method get released?
Second question, if in case I have to use [NSString alloc] to create my own string object. Where and how should I release it?
Thanks in advance
Leo
It isn't true that the object will be autoreleased before you retain it. The details of when the pool gets drained are unimportant to answer this question, except that it can't happen during your code unless you call drain or release on the pool. If your function calls another function, except in some specific edge cases both the function you call and the function you called from need to exit before that thread can do anything else. The autorelease pool is thread-specific.
To answer your second question, if you alloc an object you should release it when you've finished using it. Simple as that. That includes when you pass it to other code that needs it, because it should be up to that other code to claim ownership if it needs to.
This code worked for me, but I am concerned that result is allocated by a convenient method thus may be auto-released before it got retained by the label.
Yes, it will be autoreleased because it is returned by a method whose name does not contain new, alloc or copy. No, this won't happen before the calling method viewDidLoad returns.
In fact, the autorelease-pool, to which it's added will probably be the one set-up and teared-down by the runloop, so nothing is going to happen to it until the end of the current iteration through the runloop.

retain with objective-c

I have a question about a retain and a NSString, if I have a method who a return a NSString, and I put the return NSString in a nsstring variable, I must do a retain or not?
NSString *myString = #"";
myString = [self methodWhoReturnString]; // I must do this?
myString = [[self methodWhoReturnString]retain]; // Or I must do this?
The Apple Developer Documentation on Memory Management explains the scenarios where you retain/release objects.
Simply put, if you want the string to stick around, you need to retain it until you're finished with it. If that is just the scope of the current function, you can get away without retaining it as if the string is already autorelease'd (likely) it won't get released until your function finishes and the current AutoReleasePool is purged.
Bear in mind that an NSString * could actually be pointing to an NSMutableString *. If it matters to you if the string is changed by some other function without you realizing, be sure to copy it: NSString * myCopyOfString = [mystring copy];
If the string is set to autorelease, which it most likely is, then yes you will need to retain it somehow. I would suggest doing this though:
myString = [[self methodWhoReturnString] copy];
this ensures you have retained the data in the string not just a reference to a string that might still be controlled elsewhere. Be sure you release your copy later!
Usually, methodWhoReturnString would return an autoreleased string, which means you should retain it if you want to keep it around.
So, if methodWhoReturnString is your method, I believe that to keep with convention you should return [stringToReturn autorelease]; from that method, and then retain it if you want to keep it.
You use retain if you're going to be using myString at a later point in time (i.e. after the current method has returned) to prevent it being autoreleased.
You don't need to use retain if it's just a temporary variable used within the current method, since in that case you do want it to be autoreleased.
One special case is properties. If you call self.blah = foo, you don't need to retain foo, since the setBlah: method should do it for you.
(there's a whole load of other complexities and edge cases, but this is a good rule of thumb to get you started on understanding what to do)
Given the code you provided, you shouldn't call -retain. In your example, the return value of a method that returns an instance of NSString is assigned to myString, an automatic local variable. If the assignment had been made to an instance variable or a static variable, you would want to call either retain or copy to guarantee that the reference remains valid beyond the end of the local scope.
In this case though, the reference to the NSString instance is stored in a variable that will be destroyed automatically at the end of the local scope, so your code needn't concern itself with the object's lifetime.
Any method that has alloc, new or copy in it automatically retains and infers that you have ownership of the object. All others shouldn't. It would be helpful if you had more context though. If we are in a contained method where this string is used briefly, then you probably don't need to retain. If it is going to be used for a while, you might want to use the #synthesize syntax to make it a property of the class you are in. When you use #property and #synthesize and call something like self.myProperty = something it will automatically retain.

Memory leak found with clang but cant release and autorelease crashes

I have a class that builds a request based on a few passed in variables. The class also has all the delegate methods to receive the data and stores it in a property for the calling class to retrieve.
When the class initializes it creates a connection and then returns itself:
NSURLConnection *connection;
if (self = [super init]) {
self.delegate = theDelegate;
...some code here...
connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self startImmediately:YES];
}
return self;
So I can't release it normally and if I autorelease it crashes. Is it the job of the calling class to release? And if so does just releasing the initilised object also release connection or do you have to release it specifically? If so how would you?
Thanks
Make connection an instance variable and release it on-demand. The question "who" should release the object depends strictly on your object semantics and hierarchy.
Why are you opening an NSURLConnection within a constructor?
Typically, your constructor shouldn't perform this type of work. If the connection is associated to the object, I would make connection a property of the object and [connection release]; within the object's dealloc method.
Remember that you shouldn't place all your faith in Clang. It can and does report false negatives and false positives.
Clang is getting better every day, but it still in its infancy right now. It's great that it's integrated with Xcode so nicely, but just keep in mind that it does have some flaws.
In this case, it depends on the scope of the variable you're storing the connection object in. If it's declared as an instance variable, then it should be ok, as long as you release it in dealloc or at some other point when you're done with it.
If, like you've posted in your question, the declaration of connection is local to your init method, then Clang is correctly reporting a leak. You should make connection an instance variable or property and ensure you release it in dealloc or when you're finished with it.