Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application crashes #168

Closed
traustitj opened this issue Apr 18, 2011 · 5 comments
Closed

Application crashes #168

traustitj opened this issue Apr 18, 2011 · 5 comments

Comments

@traustitj
Copy link

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 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.3 and I test on all apple devices except original iPhones.

@traustitj
Copy link
Author

Instead of releasing the queue inside the viewDidUnload: I release the code inside viewWillDissapear:animated:

Although I probably are doing an overkill, this works great :

  • (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    for (ASIHTTPRequest *req in [queue operations]) {
    [req clearDelegatesAndCancel];
    [req setDelegate:nil];
    [req setDidFailSelector:nil];
    [req setDidFinishSelector:nil];
    }
    [queue cancelAllOperations];
    [queue setDelegate:nil];
    }

@zeroemissionart
Copy link

HI i have the same problem but i haven't resolve with method viewWillDisappear.

Can you help me?

Thank you

@traustitj
Copy link
Author

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.

@Ricardo1980
Copy link

Does anyone know the reason of this crash?
I'd like to use delegation pattern instead of blocks.
Thanks a lot.

@followben
Copy link

@Ricardo1980 It's because your ASIHTTPRequest instance is still has it's delegate property pointing to an object that is now gone.

Typically this happens when you've got transient delegates (like view controllers) making requests and (even if called -clearDelegatesAndCancel on ASI in dealloc or viewDidUnload), the response has has already been passed to the main thread. So the transient delegate gets dealloc'd, and the main thread tries to call the selector on it's invalid pointer. You can verify if this is your problem by setting an exception breakpoint and typing po $eax in gdb.

You can shut down the window for failure by calling -clearDelegatesAndCancel as early as possible, or as @traustitj mentions: if you're set on delegation, either make sure your ASI delegate is guaranteed to be there when the response executes (usually by making it a shared instance via dispatch_once_t), or just get comfortable with blocks. If you need more powerful block handlers than ASI, AFNetworking has some nice block-based APIs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants