Skip to content

Instantly share code, notes, and snippets.

@steipete
Created November 27, 2011 13:28
Show Gist options
  • Save steipete/1397553 to your computer and use it in GitHub Desktop.
Save steipete/1397553 to your computer and use it in GitHub Desktop.
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];
}
@steipete
Copy link
Author

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

@steipete
Copy link
Author

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?

@insanehunter
Copy link

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

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

@steipete
Copy link
Author

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

@insanehunter
Copy link

Oh, that's really tricky then.

@insanehunter
Copy link

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

@steipete
Copy link
Author

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

@shashankpatel
Copy link

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