9
votes

I have a navigation based app. Press a button on main view, then I push a new view to the navigation controller. All pretty basic stuff.

When the new view is loaded, I do an ASIHTTPRequest to fetch some json data, which is a list of image urls. Then I do a for loop, create a bunch of ASIHTTPRequests, add them to a queue and then run the queue.

But if I click on the back button before the queue is finished, the app crashes, this app displays houses and lets say you pick the wrong house, click back very quickly, before any photo is displayed, bumm crash.

This thread http://groups.google.com/group/asihttprequest/browse_thread/thread/3d4815198aa889b9 explains my problem real well, except I do cancel all requests on view did unload, set delegate to nil and release the queue.

Still I crash. I crash pretty much every time if I use 3G, but on wifi it is real hard to make it crash, but quite doable.

In almost 80% instances the debugger jumps to this line in ASIHTTPRequest.m

(void)requestReceivedResponseHeaders:(NSMutableDictionary *)newResponseHeaders { 
  if ([self error] || [self mainRequest]) { return; }  
--> if (delegate && [delegate respondsToSelector:didReceiveResponseHeadersSelector]) {

Many many cases it jumps to :

(void)requestReceivedResponseHeaders:(NSMutableDictionary *)newResponseHeaders { 
  if ([self error] || [self mainRequest]) { return; }    
---> if (delegate && [delegate respondsToSelector:didReceiveResponseHeadersSelector]) {  

Ad in a handful of instances it goes to my main loop

int main(int argc, char *argv[]) {  
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
--> int retVal = UIApplicationMain(argc, argv, nil, nil); with SIGBART error [pool release]; return retVal;  

I am using MBP and MacPro, latest OS X, Xcode 4.0.2 and I test on all apple devices except original iPhones.

I really don't want to re-write my whole app, but is there anything else out there that compares with ASIHTTPRequest ?

4

4 Answers

12
votes

Try cancelling and unsetting the delegate in -viewWillUnload rather than -viewDidUnload. I suspect the window of time in which it's actually unloading (between calling those two UIViewController methods) is the time period when you're crashable. The delegate has gone away, but you haven't told your ASIHTTPRequest object that yet.

4
votes

The error is that the delegate is still set.

I have found 2 ways to fix this.

The way I consider ugly is that you make a universal delegate that does all network traffic and is instantiated when the app is first run. I actually used the app delegate and listen to nsnotification center messages. It works like a charm, the app never crashes, but I think it is not optimal.

The best way is to not set the delegate and not use "setDidFinishSelector", but instead use "setCompletionBlock:^". This will only work on devices running iOS 4.0 and up, which is more than 90-95% and growing. This is just an awesome way and will not crash the application.

3
votes

You won't find anything better that ASIHTTPRequest, the problem will be how you are using it and vanishing delegates on navigation are a common problem to have to deal with.

It sounds like your problem relates to the viewcontroller that is handling the queue being destroyed due to user navigation. I find the best way of solving these issues is to have a central model class that handles all my communications and keep that class throughout the application lifecycle.

That way you don't get unexplained crashes when delegates have vanished unexpectedly.

Option 2

Another approach can be to disable user navigation until the network operation completes. Put a modal view over the entire screen that shows a uiactivityview so the user knows their actions are being blocked. Then you can fade the modal view off when the data has arrived. If you design the screen nicely with a gradient so the background just dims a bit, this can look OK. But it's not really the best approach - you should fix the delegate AWOL instead.

We probably need to see more of the code relating to the queue creation, destruction etc to find the exact issue.

1
votes

Your application delegate can own an array of request queues. The array lives independent of the state of the navigation controller stack and associated views. Instead of tying requests to a view controller in the nav stack, and having to do UI tricks to block popping back to a parent view, you could add requests to an app delegate queue instance, or stop all requests and empty the queue, etc.