Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSOperation, observer and thread error

Tags:

iphone

sdk

I've got a problem with NSOperation and observer.

I've a tabbarcontroller and a splashController. I want the splashscreen load and download the file and when the file is downloaded make the tabbarcontroller appear to the screen.

The problem is that i 've an error :

bool _WebTryThreadLock(bool), 0x3d2fa90: 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 my code :

- (void)applicationDidFinishLaunching:(UIApplication *)application {

    queue = [[NSOperationQueue alloc] init];


    NSString *path = [NSString stringWithFormat:@"%@flux.xml",DOCPATH];
    //Le fichier existe dans le repertoire des documents
    if([[NSFileManager defaultManager] fileExistsAtPath:path])
        [window addSubview:tabBarController.view];
    else
    {
        splash = [[SplashController alloc] init];
        [window addSubview:splash.view];
    }

    DataLoadOperation *operation = [[DataLoadOperation alloc] initWithURL:[NSURL URLWithString:@"http://sly.33.free.fr/flux.xml"]];
    [self.queue addOperation:operation];
    [operation addObserver:self forKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew context:nil];


}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    [window addSubview:tabBarController.view];
    [window makeKeyAndVisible];
    NSLog(@"fini");

}

Could anyone help me ?

like image 787
Sly33 Avatar asked Aug 07 '09 11:08

Sly33


1 Answers

Key-value observing notifications occur on the same thread in which the observed property was changed on. Apple mentions the following warning in the NSOperation class reference:

"Although you can attach observers to these properties, you should not use Cocoa bindings to bind them to elements of your application’s user interface. Code associated with your user interface typically must execute only in your application’s main thread. Because an operation may execute in any thread, any KVO notifications associated with that operation may similarly occur in any thread."

In your observeValueForKeyPath:ofObject:change:context: method, you should perform any UIKit operations on the main thread. Since you're performing multiple steps in there, you might actually want to create another method in your observing class called -dataLoadingFinished which you can call on the main thread from inside observe:…. You can then include all of your UI calls in there, rather than having to call performSelectorOnMainThread for each one:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
  [self performSelectorOnMainThread:@selector(dataLoadingFinished:) withObject:nil waitUntilDone:YES];
}

Even in cases where threading is not an issue, it is customary to define separate methods to actually implement each observation action, to prevent the observe:… from growing too large.

Also note that even though you are only observing one property, it is still better practice to validate that the property you are interested in is the one prompting the change notification. See Dave Dribin's article Proper KVO Usage for the best way in which to do this.

like image 54
Sean Patrick Murphy Avatar answered Sep 30 '22 14:09

Sean Patrick Murphy