iOS démarrer le fil d'arrière-plan

117

J'ai un petit sqlitedb dans mon appareil iOS. Lorsqu'un utilisateur appuie sur un bouton, je récupère les données de sqlite et je les montre à l'utilisateur.

Cette partie de récupération, je veux le faire dans un thread d'arrière-plan (pour ne pas bloquer le thread principal de l'interface utilisateur). Je fais ça comme ça -

[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];

Après la récupération et un peu de traitement, je dois mettre à jour l'interface utilisateur. Mais puisque (comme bonne pratique), nous ne devons pas effectuer de mise à jour de l'interface utilisateur à partir des threads d'arrière-plan. J'appelle un selectorfil principal comme ça -

[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];

Mais mon application plante dans la première étape. c'est-à-dire démarrer un fil d'arrière-plan. N'est-ce pas un moyen de démarrer des threads d'arrière-plan dans iOS?

MISE À JOUR 1: Après [self performSelectorInBackground....avoir obtenu ce stacktrace, aucune information quoi que ce soit -

entrez la description de l'image ici

MISE À JOUR 2: J'ai même essayé de démarrer un fil d'arrière-plan comme celui-ci - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];mais j'obtiens toujours le même stacktrace.

Juste pour que je clarifie, lorsque j'effectue cette opération sur le fil principal, tout se passe bien ...

MISE À JOUR 3 C'est la méthode que j'essaie d'exécuter en arrière-plan

- (void)getResultSetFromDB:(NSMutableArray *)toProceessDocids
{
    SpotMain *mirror = [[SpotMain alloc] init];
    NSMutableArray *filteredDocids = toProceessDocids;

    if(![gMediaBucket isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForMediaBucketWithDocID:filteredDocids mBucket:gMediaBucket numRes:-1];
    if(![gMediaType isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForMediaType:filteredDocids mediaType:gMediaType numRes:-1];
    if(![gPlatform isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForPlatformID:filteredDocids platformId:@"1" numRes:-1];

    self.resultSet = [mirror FetchObjectFromDocid:filteredDocids];
    [filteredDocids release];
    [mirror release];

    [self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];
    return;
}
Srikar Appalaraju
la source
Quel journal d'erreurs / plantage obtenez-vous?
jtbandes
S'il vous plaît voir mes mises à jour ...
Srikar Appalaraju
Pouvez-vous s'il vous plaît montrer la méthode que vous appelez en arrière-plan? Et assurez-vous que l'objet docidsest conservé.
Rog
oui, le docidssont retain. Je l'ai mis en .htant que@property (nonatomic, retain) NSMutableArray *docids;
Srikar Appalaraju
Ne préfixez pas les méthodes avec get; ça devrait juste êtreresultSetFromDB:
bbum

Réponses:

270

Si vous utilisez performSelectorInBackground:withObject:pour générer un nouveau thread, le sélecteur effectué est responsable de la configuration du pool de libération automatique du nouveau thread, de la boucle d'exécution et d'autres détails de configuration - voir «Utilisation de NSObject pour générer un thread» dans le Guide de programmation des threads d'Apple .

Vous feriez probablement mieux d'utiliser Grand Central Dispatch , cependant:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self getResultSetFromDB:docids];
});

GCD est une technologie plus récente, plus efficace en termes de surcharge mémoire et de lignes de code.


Mis à jour avec une pointe de chapeau à Chris Nolet , qui a suggéré un changement qui simplifie le code ci-dessus et suit les derniers exemples de code GCD d'Apple.

Scott Forbes
la source
cool! ne savait pas cela. Est-ce que cela s'applique [NSThread detachNewThreadSelector:@selector....également?
Srikar Appalaraju
Oui. Selon la documentation Apple, appeler performSelectorInBackground:withObject:"est le même que si vous appeliez la detachNewThreadSelector:toTarget:withObject:méthode de NSThreadavec l'objet actuel, le sélecteur et l'objet paramètre en tant que paramètres."
Scott Forbes
Y a-t-il une différence entre (unsigned long)NULLet 0dans ce domaine?
Sti
4
@Sti de Apple Dev Docs : Remarque: Le deuxième argument de la fonction dispatch_get_global_queue est réservé pour une future expansion. Pour l'instant, vous devez toujours passer 0 pour cet argument.
Jawad Al Shaikh
Dois-je ensuite utiliser performSelectorOnMainThread pour mettre à jour l'interface utilisateur avec les résultats de l'opération ou il existe un moyen plus cohérent de mettre à jour l'interface utilisateur avec GCD?
Ilya Denisov le
9

Eh bien, c'est assez facile en fait avec GCD. Un flux de travail typique serait quelque chose comme ceci:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        // Perform async operation
        // Call your method/function here
        // Example:
        // NSString *result = [anObject calculateSomething];
                dispatch_sync(dispatch_get_main_queue(), ^{
                    // Update UI
                    // Example:
                    // self.myLabel.text = result;
                });
    });

Pour en savoir plus sur GCD, vous pouvez consulter la documentation d'Apple ici

Pawan Ahire
la source
4

Activez NSZombieEnabled pour savoir quel objet est libéré puis accédé. Vérifiez ensuite si cela getResultSetFromDB:a quelque chose à voir avec cela. Vérifiez également s'il y docidsa quelque chose à l'intérieur et s'il est retenu.

De cette façon, vous pouvez être sûr qu'il n'y a rien de mal.

Nicolas S
la source
Veuillez copier la ligne que vous avez utilisée et qui s'exécute correctement sur le thread principal.
Nicolas S
J'utilise ceci à partir du fil principal et au moins, il frappe cette méthode au lieu de s'écraser brusquement -[self getResultSetFromDB:docids];
Srikar Appalaraju
avez-vous activé ce que je vous ai dit?
Nicolas S
Mettez un point d'arrêt dans cette ligne: SpotMain * mirror = [[SpotMain alloc] init]; et dites-moi si son coup et, si tehn, quelle ligne plante. Activez les zombies s'il vous plaît afin que nous puissions obtenir un journal des erreurs clair.
Nicolas S
oui, j'ai activé les zombies. J'obtiens ceci - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet release]: message envoyé à l'instance désallouée 0x2bff80 2011-08-14 12: 49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): Objet 0x2c0cc0 de la classe __NSCFData libéré automatiquement sans pool en place - fuite juste. Also when I try to call this method from background thread I do not reach SpotMain * miroir ... `, Il plante peu de temps après être entré dans le thread d'arrière-plan ...
Srikar Appalaraju
2

La bibliothèque sqlite par défaut fournie avec iOS n'est pas compilée à l'aide de la macro SQLITE_THREADSAFE activée. Cela pourrait être une raison pour laquelle votre code plante.

Mugunth
la source
2

Réponse de Swift 2.x:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
Crashalot
la source