iosobjective-cconcurrencynsoperationperformselector

App crashes when I pop my navigation controller while NSOperation performs performSelectorOnMainThread


I'm following the NSOperation tutorial: http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues to load images in my own view controller's tableview. While the images are loading, if I pop the view controller from my navigation controller, the app crashes with the error: EXC_BAD_ACCESS on the line:

[(NSObject *)self.delegate performSelectorOnMainThread:@selector(imageDownloaderDidFinish:) withObject:self waitUntilDone:NO];

The line tells my delegate(view controller) to perform a method, but I already popped my view controller. How do I prevent this from happening? I tried cancel my operation queue in the viewDidUnload of my view controller, but it doesn't work. Also tried perform a check if my delegate is nil before performing the method. Any help would be greatly appreciated.


Solution

  • How are you popping your view controller?

    For simplicity, let's name the method where you pop your view controller pop.

    I would implement something in pop where before you actually pop the view controller you call cancel on your NSOperation (perhaps show a loading spinner or an overlay here). Then wait until the cancelled and finished values are true and executing is false (or at least check some of these and experiment to see which ones you can get away with not checking).

    The important thing is that there is logic inside each block you add to the NSOperation that checks to see if cancel has been called. But, this is tricky as if your block just checks at the beginning if it should cancel it might be fine at that point to carry on. Perhaps it then goes on to perform some async task and if at that point you call cancel it won't do anything as your block is no longer guarding against a cancellation call.

    My guess is that you're calling cancel but not actually waiting until the operation has gone away, done its KVO and cancelled everything.

    I'm not sure if your question purely regarded learning about NSOperation but, if it wasn't, AFAIK, AFNetworking does a great job at all of this stuff. Particularly at loading ImageViews asynchronously (which is what that tutorial seems to be covering with that NSOperation stuff). AFNetworking adds a category to UIImageView called UIImageView+AFNetworking that provides a method called setImageWithURL:. This takes care of all these sort of problems and provides caching as well. Install AFNetworking, then

    #import "UIImageView+AFNetworking.h"

    and call

    [self.imageView setImageWithURL:imageURL];.

    I know that this last bit doesn't specifically answer your question but hopefully the rest helps.