iOS avvia thread in background


117

Ho un piccolo sqlitedb nel mio dispositivo iOS. Quando un utente preme un pulsante, prendo i dati da sqlite e li mostro all'utente.

Questa parte di recupero voglio farlo in un thread in background (per non bloccare il thread principale dell'interfaccia utente). Lo faccio così -

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

Dopo il recupero e un po 'di elaborazione, devo aggiornare l'interfaccia utente. Ma poiché (come buona pratica) non dovremmo eseguire l'aggiornamento dell'interfaccia utente da thread in background. Chiamo un selectorsu mainthread in questo modo -

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

Ma la mia app si arresta in modo anomalo nel primo passaggio. cioè l'avvio di un thread in background. Non è questo un modo per avviare i thread in background in iOS?

AGGIORNAMENTO 1: Dopo [self performSelectorInBackground....aver ricevuto questo stacktrace, nessuna informazione come mai -

inserisci qui la descrizione dell'immagine

AGGIORNAMENTO 2: Ho anche provato ad avviare un thread in background in questo modo, [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];ma ottengo comunque lo stesso stacktrace.

Giusto per chiarire, quando eseguo questa operazione sul thread principale tutto gira liscio ...

AGGIORNAMENTO 3 Questo è il metodo che sto cercando di eseguire in background

- (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;
}

Quale registro errori / crash ottieni?
jtbandes

Si prega di consultare i miei aggiornamenti ...
Srikar Appalaraju

Puoi per favore mostrare il metodo che stai chiamando in background? E assicurati che l'oggetto docidsvenga conservato.
Rog

sì, lo docidssono retain. L'ho inserito .hcome@property (nonatomic, retain) NSMutableArray *docids;
Srikar Appalaraju

Non anteporre ai metodi get; dovrebbe essere soloresultSetFromDB:
bbum

Risposte:


270

Se si utilizza performSelectorInBackground:withObject:per generare un nuovo thread, il selettore eseguito è responsabile della configurazione del pool di rilascio automatico del nuovo thread, del ciclo di esecuzione e di altri dettagli di configurazione - vedere "Utilizzo di NSObject per generare un thread" nella Guida alla programmazione dei thread di Apple .

Probabilmente faresti meglio a usare Grand Central Dispatch , però:

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

GCD è una tecnologia più recente ed è più efficiente in termini di overhead di memoria e righe di codice.


Aggiornato con una punta di cappello a Chris Nolet , che ha suggerito una modifica che semplifica il codice sopra e tiene il passo con gli ultimi esempi di codice GCD di Apple.


freddo! non lo sapevo. Questo vale [NSThread detachNewThreadSelector:@selector....anche per?
Srikar Appalaraju

Sì. Secondo i documenti di Apple, chiamare performSelectorInBackground:withObject:"è lo stesso che chiamare il detachNewThreadSelector:toTarget:withObject:metodo di NSThreadcon l'oggetto, il selettore e l'oggetto parametro correnti come parametri".
Scott Forbes

C'è una differenza tra (unsigned long)NULLe 0in questa materia?
Sti

4
@Sti da Apple Dev Docs : Nota: il secondo argomento della funzione dispatch_get_global_queue è riservato per espansioni future. Per ora, dovresti sempre passare 0 per questo argomento.
Jawad Al Shaikh

Devo quindi utilizzare performSelectorOnMainThread per aggiornare l'interfaccia utente con i risultati dell'operazione o esiste un modo più coerente per aggiornare l'interfaccia utente con GCD?
Ilya Denisov

9

In realtà è abbastanza facile con GCD. Un tipico flusso di lavoro sarebbe qualcosa del genere:

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;
                });
    });

Per ulteriori informazioni su GCD puoi dare un'occhiata alla documentazione di Apple qui


4

Abilita NSZombieEnabled per sapere quale oggetto viene rilasciato e quindi accedere. Quindi controlla se getResultSetFromDB:ha qualcosa a che fare con questo. Controlla anche se docidsha qualcosa all'interno e se viene trattenuto.

In questo modo puoi essere sicuro che non c'è niente di sbagliato.


Si prega di copiare la riga che hai usato che funziona senza problemi sul thread principale.
Nicolas S

Lo uso dal thread principale e almeno colpisce quel metodo invece di bloccarsi bruscamente -[self getResultSetFromDB:docids];
Srikar Appalaraju

hai abilitato quello che ti ho detto?
Nicolas S

Inserite un punto di interruzione in questa riga: SpotMain * mirror = [[SpotMain alloc] init]; e dimmi se viene colpito e, se tehn, quale riga si blocca. Abilita gli zombi, per favore così possiamo ottenere un registro degli errori chiaro.
Nicolas S

sì, ho abilitato gli zombi. Ho questo - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet release]: messaggio inviato all'istanza deallocata 0x2bff80 2011-08-14 12: 49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): Oggetto 0x2c0cc0 della classe __NSCFData rilasciato automaticamente senza pool in posizione - solo fuoriuscita . Also when I try to call this method from background thread I do not reach SpotMain * mirror ... `, Si arresta in modo
anomalo

2

La libreria sqlite predefinita fornita con iOS non viene compilata utilizzando la macro SQLITE_THREADSAFE su. Questo potrebbe essere un motivo per cui il tuo codice si blocca.


2

Risposta rapida 2.x:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.