2009-08-07 8 views
6

J'ai un problème avec NSOperation et observateur. J'ai un tabbarcontroller et un splashController. Je veux charger le splashscreen et télécharger le fichier et quand le fichier est téléchargé faire le tabbarcontroller apparaître à l'écran.NSOpération, observateur et erreur de fil

Le problème est que j'ai une erreur:

bool _WebTryThreadLock (bool), 0x3d2fa90: a essayé d'obtenir le verrouillage web à partir d'un fil autre que le fil conducteur ou le fil de la nappe. Cela peut être le résultat d'un appel à UIKit à partir d'un thread secondaire. Crashing maintenant ...

Voici mon 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"); 

} 

Quelqu'un pourrait-il me aider?

Répondre

20

Les notifications d'observation de valeur-clé se produisent sur le même thread dans lequel la propriété observée a été modifiée. Apple mentionne l'avertissement suivant dans la référence de classe NSOperation:

« Bien que vous pouvez joindre des observateurs à ces propriétés, vous ne devriez pas utiliser les liaisons Cocoa pour les lier à des éléments de l'interface utilisateur de votre application de code associé à l'interface utilisateur. En général, il ne doit s'exécuter que dans le thread principal de votre application.Parce qu'une opération peut s'exécuter dans n'importe quel thread, toutes les notifications KVO associées à cette opération peuvent se produire de la même manière dans n'importe quel thread. "

Dans votre méthode observeValueForKeyPath:ofObject:change:context:, vous devez effectuer toutes les opérations UIKit sur le thread principal. Puisque vous effectuez plusieurs étapes, vous pouvez créer une autre méthode dans votre classe d'observation appelée -dataLoadingFinished que vous pouvez appeler depuis le fil principal à l'intérieur de observe:…. Vous pouvez ensuite inclure toutes votre interface utilisateur appelle là-bas, plutôt que d'avoir à appeler performSelectorOnMainThread pour chacun:

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

Même dans les cas où le filetage est pas un problème, il est d'usage de définir des méthodes distinctes pour mettre en œuvre effectivement chaque action d'observation, pour empêcher le observe:… de devenir trop grand. Notez également que même si vous observez uniquement une propriété, il est toujours préférable de valider que la propriété qui vous intéresse est celle qui invite la notification de modification. Voir l'article de Dave Dribin Proper KVO Usage pour le meilleur moyen de le faire.