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.