Mam mały sqlitedb na moim urządzeniu z iOS. Kiedy użytkownik naciska przycisk, pobieram dane z sqlite i pokazuję je użytkownikowi.
Ta część pobierania chcę to zrobić w wątku w tle (aby nie blokować głównego wątku interfejsu użytkownika). Robię to tak -
[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];
Po pobraniu i trochę przetworzeniu muszę zaktualizować interfejs użytkownika. Ale ponieważ (jako dobra praktyka) nie powinniśmy przeprowadzać aktualizacji interfejsu użytkownika z wątków w tle. Wzywam takiego selector
głównego wątku -
[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];
Ale moja aplikacja ulega awarii w pierwszym kroku. tj. rozpoczęcie wątku w tle. Czy to nie jest sposób na uruchamianie wątków w tle w iOS?
AKTUALIZACJA 1: Po tym, [self performSelectorInBackground....
jak otrzymam ten ślad stosu, nie ma żadnych informacji -
AKTUALIZACJA 2: Próbowałem nawet rozpocząć wątek w tle w ten sposób -
[NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];
ale nadal otrzymuję ten sam ślad stosu.
Tylko dla wyjaśnienia, kiedy wykonuję tę operację na głównym wątku, wszystko działa gładko ...
UPDATE 3 To jest metoda, którą próbuję uruchomić w tle
- (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;
}
źródło
docids
jest zachowany.docids
sąretain
. Umieściłem to.h
jako@property (nonatomic, retain) NSMutableArray *docids;
get
; tak powinno byćresultSetFromDB:
Odpowiedzi:
Jeśli używasz
performSelectorInBackground:withObject:
do tworzenia nowego wątku, to wykonany selektor jest odpowiedzialny za ustawienie puli autorelease nowego wątku, pętli uruchamiania i innych szczegółów konfiguracyjnych - zobacz „Używanie NSObject do tworzenia wątku” w Przewodniku programowania wątków Apple .Prawdopodobnie lepiej byłoby, gdybyś skorzystał z Grand Central Dispatch :
GCD jest nowszą technologią i jest bardziej wydajna pod względem narzutu pamięci i wierszy kodu.
Zaktualizowano wskazówką dotyczącą kapelusza dla Chrisa Noleta , który zasugerował zmianę, która uprości powyższy kod i dotrzymuje kroku najnowszym przykładom kodu GCD firmy Apple.
źródło
[NSThread detachNewThreadSelector:@selector....
również?performSelectorInBackground:withObject:
„jest takie samo, jak wywołaniedetachNewThreadSelector:toTarget:withObject:
metodyNSThread
z bieżącym obiektem, selektorem i obiektem parametrów jako parametrami”.(unsigned long)NULL
iw0
tej kwestii?Cóż, jest to całkiem proste w przypadku GCD. Typowy przepływ pracy wyglądałby tak:
Więcej informacji na temat GCD można znaleźć w dokumentacji firmy Apple tutaj
źródło
Włącz NSZombieEnabled, aby wiedzieć, który obiekt jest zwalniany, a następnie dostępny. Następnie sprawdź, czy
getResultSetFromDB:
ma z tym coś wspólnego. Sprawdź również, czydocids
coś jest w środku i czy jest zachowane.W ten sposób możesz mieć pewność, że wszystko jest w porządku.
źródło
[self getResultSetFromDB:docids];
. Also when I try to call this method from background thread I do not reach
SpotMain * lustro ... `, zawiesza się zaraz po wejściu na wątek tła ...Domyślna biblioteka sqlite dostarczana z systemem iOS nie jest kompilowana przy użyciu makra SQLITE_THREADSAFE na. Może to być powód awarii kodu.
źródło
Odpowiedź Swift 2.x:
źródło