iOS startet Hintergrund-Thread

117

Ich habe ein kleines sqlitedb in meinem iOS-Gerät. Wenn ein Benutzer eine Taste drückt, rufe ich die Daten von SQLite ab und zeige sie dem Benutzer.

Diesen Abrufteil möchte ich in einem Hintergrund-Thread machen (um den UI-Haupt-Thread nicht zu blockieren). Ich mache das so -

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

Nach dem Abrufen und ein wenig Verarbeitung muss ich die Benutzeroberfläche aktualisieren. Da wir jedoch (als bewährte Methode) keine Aktualisierung der Benutzeroberfläche über Hintergrundthreads durchführen sollten. Ich rufe einen selectorOn-Mainthread so an -

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

Aber meine App stürzt im ersten Schritt ab. dh einen Hintergrund-Thread starten. Ist dies nicht eine Möglichkeit, Hintergrund-Threads in iOS zu starten?

UPDATE 1: Nachdem [self performSelectorInBackground....ich diesen Stacktrace erhalten habe, gibt es überhaupt keine Informationen -

Geben Sie hier die Bildbeschreibung ein

UPDATE 2: Ich habe sogar versucht, einen Hintergrund-Thread wie diesen zu starten - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];aber ich bekomme immer noch den gleichen Stacktrace.

Nur damit ich klarstelle, wenn ich diesen Vorgang am Hauptthread durchführe, läuft alles reibungslos ...

UPDATE 3 Dies ist die Methode, die ich aus dem Hintergrund ausführen möchte

- (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
quelle
Welches Fehler- / Absturzprotokoll erhalten Sie?
Jtbandes
Bitte sehen Sie meine Updates ...
Srikar Appalaraju
Können Sie bitte die Methode, die Sie aufrufen, im Hintergrund zeigen? Und stellen Sie sicher, dass das Objekt erhalten docidsbleibt.
Rog
ja, docidssind retain. Ich habe es .h@property (nonatomic, retain) NSMutableArray *docids;
eingegeben
Stellen Sie Methoden keine Präfixe vor get; das sollte nur seinresultSetFromDB:
bbum

Antworten:

270

Wenn Sie performSelectorInBackground:withObject:einen neuen Thread erzeugen, ist der durchgeführte Selektor für das Einrichten des Autorelease-Pools, der Ausführungsschleife und anderer Konfigurationsdetails des neuen Threads verantwortlich - siehe "Verwenden von NSObject zum Spawnen eines Threads" im Apple Threading-Programmierhandbuch .

Mit Grand Central Dispatch sind Sie wahrscheinlich besser dran :

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

GCD ist eine neuere Technologie und in Bezug auf Speicheraufwand und Codezeilen effizienter.


Aktualisiert mit einer Hutspitze an Chris Nolet , der eine Änderung vorschlug, die den obigen Code einfacher macht und mit den neuesten GCD-Codebeispielen von Apple Schritt hält.

Scott Forbes
quelle
cool! wusste das nicht. Gilt das [NSThread detachNewThreadSelector:@selector....auch für?
Srikar Appalaraju
Ja. Gemäß den Apple-Dokumenten ist der Aufruf von performSelectorInBackground:withObject:"dasselbe, als ob Sie die detachNewThreadSelector:toTarget:withObject:Methode NSThreadmit dem aktuellen Objekt, dem Selektor und dem Parameterobjekt als Parameter aufgerufen hätten ."
Scott Forbes
Gibt es einen Unterschied zwischen (unsigned long)NULLund 0in dieser Angelegenheit?
Sti
4
@Sti von Apple Dev Docs : Hinweis: Das zweite Argument für die Funktion dispatch_get_global_queue ist für zukünftige Erweiterungen reserviert. Im Moment sollten Sie für dieses Argument immer 0 übergeben.
Jawad Al Shaikh
Sollte ich dann performSelectorOnMainThread verwenden, um die Benutzeroberfläche mit den Operationsergebnissen zu aktualisieren, oder gibt es eine konsistentere Möglichkeit, die Benutzeroberfläche mit GCD zu aktualisieren?
Ilya Denisov
9

Nun, das ist mit GCD eigentlich ziemlich einfach. Ein typischer Workflow wäre ungefähr so:

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

Weitere Informationen zu GCD finden Sie in der Dokumentation von Apple hier

Pawan Ahire
quelle
4

Aktivieren NSZombieEnabled zu wissen , welches Objekt freigegeben wird und dann abgerufen. Dann prüfen Sie, ob das getResultSetFromDB:etwas damit zu tun hat. Überprüfen Sie auch, ob docidssich etwas im Inneren befindet und ob es aufbewahrt wird.

Auf diese Weise können Sie sicher sein, dass nichts falsch ist.

Nicolas S.
quelle
Bitte kopieren Sie die von Ihnen verwendete Zeile, die im Hauptthread reibungslos funktioniert.
Nicolas S
Ich benutze dies vom Haupt-Thread & zumindest trifft es diese Methode, anstatt abrupt abzustürzen -[self getResultSetFromDB:docids];
Srikar Appalaraju
Hast du aktiviert, was ich dir gesagt habe?
Nicolas S
Setzen Sie einen Haltepunkt in diese Zeile: SpotMain * mirror = [[SpotMain alloc] init]; und sag mir, ob es getroffen wird und wenn tehn, welche Linie abstürzt. Aktivieren Sie bitte Zombies, damit wir ein klares Fehlerprotokoll erhalten.
Nicolas S
Ja, ich habe Zombies aktiviert. Ich erhalte Folgendes - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet release]: Nachricht an freigegebene Instanz 0x2bff80 gesendet 2011-08-14 12: 49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): Objekt 0x2c0cc0 der Klasse __NSCFData wurde automatisch freigegeben, ohne dass ein Pool vorhanden war - nur undichter . Also when I try to call this method from background thread I do not reach SpotMain * -Spiegel ... `, es stürzt kurz nach Eingabe des Hintergrundthreads ab ...
Srikar Appalaraju
2

Die mit iOS gelieferte Standard-SQLite-Bibliothek wird nicht mit dem Makro SQLITE_THREADSAFE kompiliert. Dies könnte ein Grund sein, warum Ihr Code abstürzt.

Mugunth
quelle
2

Schnelle 2.x Antwort:

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