Posts Tagged ‘WebTryThreadLock’

Solving the MBProgressHud _WebTryThreadLock Error

MBProgressHud is a really nice bit of plug in code to add fancy status and loading notifications to your iOS app quickly and easily. It looks great! Unfortunately, there’s an irritating error which cost me some time this morning, and hopefully I can save anyone else in the same position some trouble.

The error:

bool _WebTryThreadLock(bool), 0x7b9b5500: 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 appears when a method which needs to update a UI component is called directly by the MBProgressHUD object.

The most basic usage of MBProgressHUD is thus:

HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
[HUD showWhileExecuting:@selector(fetchNewData) onTarget:self withObject:nil animated:YES];

In which ‘fetchNewData’ is the method which is executed while the progress HUD is on display.

Using this technique, fetchNewData will be called on a secondary thread, which causes the crash error we’ve already experienced. UIKit, which handles all the user interface business, should only be running on the main thread, so when the secondary thread makes a move on a particular UI element, its going to throw the ‘web lock from a thread…’ error. (It should be noticed that you can update some UI components using the standard MBProgressHUD setup detailed above, but in most cases you’ll get the error.)

In the case of this example, ‘fetchNewData’ updates part of the UI, so it needs to be called on the main thread. The quick and dirty workaround I used to force it to execute where I wanted it to was to create an intermediary method which can be called by MBProgressHUD as normal but in turn calls ‘fetchNewData’ specifically on the main thread.

You could, for example, call this method ‘performFetchOnMainThread’:

-(void) performFetchOnMainThread    {
[self performSelectorOnMainThread:@selector(fetchNewData) withObject:nil waitUntilDone:YES];
}

Instead of directly calling ‘fetchNewData’ from MBProgressHUD, use it to execute ‘performFetchOnMainThread’, which uses the ‘performSelectorOnMainThread’ method to force ‘fetchNewData’ to be executed on the main thread.

This isn’t the most efficient or beautiful way to accomplish this, but it works, so if you’re getting a ‘web lock from a thread…’ error and you need to make sure your code is executed on the main thread, you can use this technique to get the job done quickly.