2011-08-14 13 views
110

Mam mały sqlitedb na moim urządzeniu z iOS. Gdy użytkownik naciśnie przycisk, pobieram dane z sqlite &, aby pokazać je użytkownikowi.Początek wątku na iOS

Ta część pobierania chcę to zrobić w wątku tła (aby nie blokować głównego wątku interfejsu użytkownika). Robię to tak jak -

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

Po ściągam & trochę obróbki, muszę zaktualizować UI. Ale ponieważ (jako dobra praktyka) nie powinniśmy wykonywać aktualizacji UI z wątków w tle. Nazywam selector na mainthread jak tak -

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

Ale mój App awarii w pierwszym etapie. to jest uruchamianie wątku tła. Czy to nie jest sposób na uruchamianie wątków w tle w iOS?

UPDATE 1: Po [self performSelectorInBackground.... otrzymuję ten StackTrace, żadnej informacji, co tak zawsze -

enter image description here

UPDATE 2: Próbowałem nawet rozpoczynając wątek tła jak tak - [NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids]; ale wciąż mam ten sam stacktrace.

Wystarczy więc, że wyjaśnienie, kiedy wykonać tę operację na wątku głównym wszystko działa gładkie ...

UPDATE 3 Jest to metoda Próbuję uruchomić od tła

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

dziennika Co błąd/awaria nie masz? – jtbandes

+0

Proszę zobaczyć moje aktualizacje ... –

+0

Czy możesz pokazać metodę, którą wywołujesz w tle? I upewnij się, że obiekt 'docids' jest zachowany. – Rog

Odpowiedz

264

Jeśli używasz performSelectorInBackground:withObject: na tarło nowy wątek, a następnie przeprowadzono selektor jest odpowiedzialny za utworzenie basen autorelease nowego wątku, należy uruchomić pętlę i inne dane konfiguracyjne - patrz "Using NSObject to Spawn a Thread" w Apple Programming Guide Threading.

Można by zapewne lepiej wyłączyć za pomocą Grand Central Dispatch, choć:

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

GCD jest nowsza technologia, i jest bardziej wydajny pod względem pamięci i napowietrznych linii kodu.


Updated z końcówką kapelusz Chris Nolet, który zaproponował zmianę sprawia, że ​​powyższy kod prostsze i utrzymuje się z najnowszych przykładów kodu GCD Apple.

+0

fajne! nie wiedziałem tego. Czy dotyczy to również "[NSThread detachNewThreadSelector: @selector ...."? –

+0

Tak. Zgodnie z dokumentacją firmy Apple wywoływanie 'performSelectorInBackground: withObject:' "jest takie samo jak w przypadku wywołania metody' detachNewThreadSelector: toTarget: withObject: 'z' NSThread' z bieżącym obiektem, selektorem i obiektem parametrów jako parametrami. " –

+0

Czy istnieje różnica między '(unsigned long) NULL' i' 0' w tej sprawie? – Sti

4

Włącz NSZombieEnabled, aby wiedzieć, który obiekt jest zwalniany, a następnie uzyskiwany do niego dostęp. Następnie sprawdź, czy getResultSetFromDB: ma coś z tym wspólnego. Sprawdź również, czy docids ma cokolwiek w środku i czy jest zachowane.

W ten sposób możesz być pewien, że nie ma w tym nic złego.

+0

Skopiuj używaną linię, która działa płynnie w głównym wątku. –

+0

Używam tego z głównego wątku i co najmniej trafienie tą metodą zamiast gwałtownie się zawiesza - '[self getResultSetFromDB: docids];' –

+0

czy masz włączone co ci powiedziałem? –

2

Domyślna biblioteka sqlite dostarczana z iOS nie jest kompilowana przy użyciu makra SQLITE_THREADSAFE. To może być powód, dla którego twój kod się zawiesza.

2

Swift 2.x odpowiedź:

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

Dobrze, że to całkiem proste faktycznie z GCD. Typowy obieg byłoby coś takiego:

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

Więcej na GCD można spojrzeć w Apple's documentation here

Powiązane problemy