2009-08-07 9 views
6

Ich habe ein Problem mit NSOperation und Beobachter.NSOperation, Beobachter und Thread Fehler

Ich habe eine tabbarcontroller und eine splashController. Ich möchte, dass der Splashscreen geladen und die Datei heruntergeladen wird und wenn die Datei heruntergeladen ist, erscheint der Bildschirm tabbarcontroller.

Das Problem ist, dass ich einen Fehler ve:

bool _WebTryThreadLock (bool), 0x3d2fa90: versucht, die Bahn arretieren von einem Thread als der Haupt-Thread andere zu erhalten, oder dem Web-Thread. Dies kann ein Ergebnis des Aufrufs zu UIKit von einem sekundären Thread sein. Crashing jetzt ...

Dies ist mein 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"); 

} 

Kann mir jemand helfen?

Antwort

20

Schlüsselwertbeobachtungsbenachrichtigungen treten in demselben Thread auf, in dem die beobachtete Eigenschaft geändert wurde. Apple erwähnt die folgende Warnung in der NSOperation Klassenreferenz:

„Obwohl Sie Beobachter dieser Eigenschaften anhängen können, sollten Sie nicht Cocoa Bindungen verwenden, um sie Elemente Ihrer Anwendung Benutzeroberfläche zu binden Code mit der Benutzeroberfläche verbunden. In der Regel muss die Ausführung nur im Hauptthread der Anwendung ausgeführt werden. Da eine Operation in einem beliebigen Thread ausgeführt werden kann, können alle KVO-Benachrichtigungen, die dieser Operation zugeordnet sind, ebenfalls in einem beliebigen Thread auftreten. "

In Ihrer observeValueForKeyPath:ofObject:change:context:-Methode sollten Sie alle UIKit-Vorgänge im Hauptthread ausführen. Da Sie dort mehrere Schritte ausführen, möchten Sie vielleicht eine andere Methode in Ihrer Beobachtungsklasse mit dem Namen -dataLoadingFinished erstellen, die Sie innerhalb von observe:… aus dem Hauptthread aufrufen können. Anschließend können Sie alle Ihre UI sind dort nennen, anstatt performSelectorOnMainThread für jeden anrufen zu müssen:

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

Selbst in Fällen, in denen Einfädeln kein Problem ist, ist es üblich, verschiedene Methoden zu definieren, um tatsächlich jede zu implementieren Beobachtungsaktion, um zu verhindern, dass das observe:… zu groß wird.

Beachten Sie auch, dass, obwohl Sie nur eine Eigenschaft beobachten, es immer noch besser ist zu überprüfen, ob die Eigenschaft, an der Sie interessiert sind, diejenige ist, die die Änderungsbenachrichtigung veranlasst. Siehe Dave Dribins Artikel Proper KVO Usage für den besten Weg, dies zu tun.