deleting delegate on dealloc without an instance variable - iphone

so i start a ASIFormDataRequest on my [viewDidLoad] in a UIViewController.
ASIFormDataRequest *detailRequest = [ASIFormDataRequest requestWithURL:url];
detailRequest.delegate = self;
[detailRequest startAsynchronous];
If my UIViewController gets released before my Request finishes, my app crashes.
If i add my ASIFormDataRequest as an instance variable for example
#property(nonatomic, retain) ASIFormDataRequest *detailRequest;
and nil the delegate on dealloc
-(void)dealloc {
if(self.detailRequest != nil) { self.detailRequest.delegate = nil; }
self.detailRequest = nil;
[super dealloc];
}
the app no longer crashes.
but i don't think it's necessary to create a instance variable just for this, especially if i have multiple requests.
is there a better way to do this?

I usually create an array and store all active requests in the array. When the request is completed I remove the request, and when the controller calls dealloc I cancel all of the requests and nil the delegate.

In order to release it you must have a pointer to it so yes, use an ivar. iars are not expensive.

By doing self.detailRequest = [ASIFormDataRequest requestWithURL:url]; I am guessing it is creating an autorelease object whose lifespan isn't bound to your controller class. If the creation and deletion of your object is bound to your controller, it's logical to use a instance variable.
More details about autorelease

You could do this:
detailRequest.delegate = [self retain];
and then call
[self autorelease];
In the ASIFormDataRequest callback method. That's what I generally tend to do, anyway.
That way, the request object retains its delegate for the duration of the request.

As this is the Asynchronous request so if you set delegate it means as soon as response comes your delegate methods will be called. Till that time your object should be alive to handle the response. So making it retain and releasing in the dealloc is fine and before than that you have to set delegate to nil. So that if response comes after releasing the method, framework should not be misguided to search for method of dead object.
To handle multiple request the best way is to create the array and number of objects you want to use. When you are done with the objects, in dealloc method iterate through each object and set delegate nil and release the object.

Related

Variable released prematurely during asynchronous request

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...)

In dealloc method set any delegate to nil is needed or not needed

I have created tableview in my view by programmatic like below
table = [[UITableView alloc] initWithFrame:CGRectMake(0, 44, 320, 370) style:UITableViewCellStyleDefault];
table.delegate = self;
table.dataSource = self;
table.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.view addSubview:table];
in dealloc method i write like below
table.delegate = nil;
table.dataSource = nil;
[table release];
table=nil;
this the better way or below one is better
[table release];
table=nil;
I want to know if i dont reset delegate and dataSource what will happen
Thanq
If you are deallocating an object that acts as the delegate to other objects, you need to make sure that you have set their delegates to nil, before you call [super dealloc] (assuming the normal pattern that objects do not retain their delegates). This is because when [super dealloc] has returned, this object is no longer a valid object and the objects it is a delegate to effectively have dangling references, if they have not been set to nil.
In this particular case, you would probably get away without doing it because your object's dealloc probably won't get called except when the UI is being dismantled and the table view no longer needs to use its delegate or data source, but don't bet on it.
From Setting delegate to nil in dealloc:
It's a defensive programming move. It's clearing out the reference to the delegate object incase something else in your object tries to access the delegate after you've told it that you're done with it. As part of your dealloc you might have a method or do something that triggers a KVO notification that makes a call to the delegate. So setting the delegate's reference to nil prevents that from happening. If it did happen you could end up with some oddball crashes that are fun to reproduce and fix.
To add to the answers above, you do not need
table = nil;
in your dealloc. It won't hurt, but it is not necessary to nil out your ivars. Your view is being dealloc'ed and therefore your ivars will no longer be accessible. You are probably confusing that with:
self.table = nil;
which can function as an alternative way to release if you are accessing the ivar via a property.
Of course if you have ARC turned on, then you don't need the release at all.
And to answer your actual question, if you don't nil out the table's delegate and datasource on the dealloc of the view....nothing will happen. They are set to the view, which is in the process of being released. In this case, you will have no issues not doing it. In theory it's good form.

Confused on using Class method with an object that has a delegate

I'm confused on Delegates. I was always under the impression that if you didn't set a delegate than it wouldn't respond to delegate callbacks. I have a crash with a Class method that releases its object.
Lets say I have a object "Something" that has a delegate set-up for handling results to the callers that care. Something uses ASIHTTPRequest to do some posts / gets asynchronously.
-(void)somethingHasResults{
//something needs to tell its listeners that its has completed (pseudo-code)
if([delegate respondsToSelector:#selector(somethingDidComplete)]){
[delegate somethingDidComplete];
}
}
But I also have a Helpers.h/.m with a series of class methods like so...
+(void)shoutItOutLoud{
//doesn't need a delegate, doesn't need a response -- just do your thing and exit
Something *something = [[Something alloc] init];
[something shouldDoSomethingAwesomeButDoesntNeedToRespond];
[something release];
}
When I use [Helpers shoutItOutLoud] I get a crash. Now the crash is actually in ASIHttpRequest.m's reportFinished, but following the trace brings me all the way back to my class method which is releasing the object before completion.
The whole point of this is that I'm surprised that I have a crash here and I'm trying to wrap my head around this. A co-worker and I got into a discussion and he says its because I'm releasing my object so the delegate is pointing at garbage. This seems wrong to me, as this class method doesn't receive the responses anyways?
I believe your problem is actually to do with not cleaning the ASIHttpRequest delegate: an ASIHttpRequest object sets its delegate to the object is called from.
So you will need to clear that delegate as well (in the Something class). Assuming that you have a property of type ASIHttpRequest, here is what I do in the dealloc method:
- (void)dealloc {
...
[_request clearDelegatesAndCancel];
[_request release];
[super dealloc];
}

Another Delegate for ASIHTTPRequest Asynchronous?

How can I create a new file containing just it's own delegate so that I can make an ASIHTTPRequest with its own asynchronous ending, and something easy enough where I just need to set [request setDelegate:self]; to something like [request setDelegate:AlternateDelegate]; and just add an include at the begining of the document to reference the AlternateDelegate delegate
I know this question is old, but in case anyone comes across it:
#Hankweb seemes to be talking about using a request as its own delegate. There are certainly situations where this works. For example, I'm working on a project that uses ASIHTTPRequest to fetch JSON from a remote source and import it into a Core Data store.
This operation (literally, as ASIHTTPRequest is a subclass of NSOperation) is almost entirely self-contained; I have a custom request on a background thread using a streaming JSON parser to import objects into a NSManagedObjectContext, which, when saved, triggers a notification that I catch internally and pass to the main thread's context using performSelectorOnMainThread:waitUntilDone:.
I'm using ASIHTTPRequest's block support to accomplish this; in my custom initWithURL: method, I set up the relevant callbacks (dataReceivedBlock, completionBlock, failureBlock, etc.). The traditional delegation pattern (using the ASIHTTPRequestDelegate protocol) should also work, though.
One gotcha: you should make sure the request doesn't retain itself too many times, or else you'll end up with a memory leak. This can be easy to miss when using multiple threads, and especially when using blocks. Instead of:
- (id)initWithURL:(NSURL *aURL) {
//...
[self setCompletionBlock:^{
[self doSomething];
}];
//...
return self;
}
Use the __weak attribute (or __block if you're not using ARC) when referencing self within the blocks:
- (id)initWithURL:(NSURL *aURL) {
//...
__weak id blockSelf = self;
[self setCompletionBlock:^{
[blockSelf doSomething];
}];
//...
return self;
}
If you don't know why this is important, make sure to read Apple's guide to blocks in Objective-C, and the ASIHTTPRequest block API documentation.
A delegate for ASIHTTPRequest is just a standard objective C object. Just create a new class, include it's header, create/get the object and set the delegate to be that object.
Have you tried this and run into a problem? If so what is the problem?

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.