web-dev-qa-db-fra.com

Exécution du gestionnaire d'achèvement de NSURLSession sur le thread principal

J'utilise NSURLSession pour obtenir les valeurs permettant de renseigner une table. Je mets à jour TableView dans le gestionnaire d'achèvement, mais l'utilisation de [[NSThread currentThread] isMainThread] m'a montré que le gestionnaire d'achèvement ne s'exécute pas dans le thread principal. Comme je ne devrais mettre à jour que l'interface utilisateur à partir du thread principal, je sais que ce n'est pas correct. Existe-t-il un moyen de déclencher une action sur le thread principal à partir du gestionnaire d'achèvement? Ou bien utiliser une NSURLSession n'est-il pas la bonne façon de s'y prendre?

NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            NSError *jsonError = nil;
            NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
            if (jsonError) {
                NSLog(@"error is %@", [jsonError localizedDescription]);
                // Handle Error and return
                return;
            }
            self.userArray = jsonUsers;
            [self.userTableView reloadData];
            if ([[NSThread currentThread] isMainThread]){
                NSLog(@"In main thread--completion handler");
            }
            else{
                NSLog(@"Not in main thread--completion handler");
            }
}] resume];
23
otter

Oui, envoyez juste votre truc de fil principal en utilisant GCD:

 NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                NSError *jsonError = nil;
                NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
                if (jsonError) {
                    NSLog(@"error is %@", [jsonError localizedDescription]);
                    // Handle Error and return
                    return;
                }

                dispatch_async(dispatch_get_main_queue(), ^{
                    self.userArray = jsonUsers;
                    [self.userTableView reloadData];
                    if ([[NSThread currentThread] isMainThread]){
                        NSLog(@"In main thread--completion handler");
                    }
                    else{
                        NSLog(@"Not in main thread--completion handler");
                    }
                });

            }] resume];
40
graver

La réponse de @ Graver est bonne. Voici une autre façon de le faire:

NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
                                                          delegate:nil
                                                     delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            NSError *jsonError = nil;
            NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
            if (jsonError) {
                NSLog(@"error is %@", [jsonError localizedDescription]);
                // Handle Error and return
                return;
            }

            self.userArray = jsonUsers;
            [self.userTableView reloadData];
            if ([[NSThread currentThread] isMainThread]){
                NSLog(@"In main thread--completion handler");
            }
            else{
                NSLog(@"Not in main thread--completion handler");
            }
        }] resume];

De cette façon, vous créez une session qui appelle le bloc d'achèvement et toutes les méthodes de délégation sur le thread principal. Vous pouvez trouver cela plus esthétique, mais vous perdez l’avantage de faire le "travail dur" en arrière-plan.

18
bugloaf

Vous pouvez essayer ceci:

[self.userTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
3
Big-O Claire

Voici le meilleur moyen de mettre à jour l'interface utilisateur à partir de blocs et du gestionnaire d'achèvement, et également lorsque vous ne précisez pas quel thread exécute votre code.

static void runOnMainThread(void (^block)(void))
{
    if (!block) return;

    if ( [[NSThread currentThread] isMainThread] ) {
        block();
    } else {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

Ceci est une méthode statique qui aura un bloc, et fonctionnera sur le thread principal, elle agira comme un 

runOnMainThread(^{
           // do things here, it will run on main thread, like updating UI

        });
3
Adnan Aftab

Swift 3.1

DispatchQueue.main.async {
    tableView.reloadData()
}
0
William Hu

envoyer une notification à la fin qui sera observée par le contrôleur de vue de table qui fera ensuite un reloadData;

cela présente l'avantage que si vous déplacez ce code de téléchargement ultérieurement vers une classe distincte, par exemple. un objet de modèle, aucune modification n'est requise et le code peut également être réutilisé dans d'autres projets sans modification

0
SPA