Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Ugly as hell workaround for UIWebView crashing on non-main thread dealloc (inside a UIView)
- (void)dealloc {
webView_.delegate = nil; // delegate is self here, so first set to nil before call stopLoading.
[webView_ stopLoading];
// UIWebView must be released in the main thread, or we get:
// Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
// This is less evil than the proposed http://stackoverflow.com/questions/945082/uiwebview-in-multithread-viewcontroller
// Calling removeFromSuperview in a dealloc is ugly and evil, but else UIView has a strong reference to UIWebView and our main-release call would be irrelevant.
if (![NSThread isMainThread]) {
[webView_ performSelectorOnMainThread:@selector(removeFromSuperview) withObject:nil waitUntilDone:YES];
}
[webView_ performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES];
[super dealloc];
}
Owner

steipete commented Nov 27, 2011

@NSElvis - if i call stopLoading first, couldn't this maybe lead to calling one of my delegate methods within the dealloc? (if the dealloc is on another thread and then context switches...)?

Owner

steipete commented Nov 27, 2011

After @anlumo1 'es suggestion, performSelectorOnMainThread immediately calls release if already on main thread, when waitUntilDone is set to YES. (http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html)

Still unsure about that removeFromSuperview.

Also - how would I solve this in ARC?

On ARC: maybe settings webView_ to nil in main thread will just work? Something like

dispatch_sync(dispatch_get_main_queue(), ^() {
        webView_ = nil;
    });
Owner

steipete commented Nov 27, 2011

@insanehunter problem is that the block will hold a strong reference to it, so in the end webView will get deallocated in the thread the block was created. (i tried that at first)

Oh, that's really tricky then.

__block variables are not retained, so probably this code should work?

__block id this = self;
dispatch_sync(dispatch_get_main_queue(), ^() {
      this.webView_ = nil;
  });

Anyway, I should go and read on blocks and GCD.

Owner

steipete commented Nov 27, 2011

__block will be retained under ARC - Apple changed this behavior. I could use __weak, but that's more overhead, and I'm not sure what other implications this might would have. (or __unsafe_unretained combined with a CFRetain/CFRelease? feels very hacky...)

Super thanks man.. You saved my a**..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment