Начальная тема iOS
У меня есть маленький sqlitedb на моем устройстве iOS. Когда пользователь нажимает кнопку, я беру данные из sqlite и показываю их пользователю.
Эта получаемая часть я хочу сделать это в фоновом потоке (чтобы не блокировать основной поток пользовательского интерфейса). Я делаю это так:
[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];
После извлечения и обработки немного мне нужно обновить интерфейс. Но поскольку (как хорошая практика), мы не должны выполнять обновление пользовательского интерфейса из фоновых потоков. Я называю selector
на mainthread так:
[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];
Но мое приложение падает на первом шаге. то есть начать фоновый поток. Разве это не способ начать фоновый поток в iOS?
ОБНОВЛЕНИЕ 1: После [self performSelectorInBackground....
я получаю этот стек, нет информации о том, что когда-либо было -
![enter image description here]()
ОБНОВЛЕНИЕ 2: Я даже пробовал, запустив фоновый поток вроде так -
[NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];
, но все же я получаю ту же стек.
Просто чтобы уточнить, когда я выполняю эту операцию в основном потоке, все работает плавно...
ОБНОВЛЕНИЕ 3 Это метод, который я пытаюсь запустить из фона
- (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;
}
Ответы
Ответ 1
Если вы используете performSelectorInBackground:withObject:
для создания нового потока, то выполненный селектор отвечает за настройку пула автоматического выпуска нового потока, цикла выполнения и других деталей конфигурации - см. "Использование NSObject для создания потока " в Руководстве по программированию потоков Apple.
Возможно, вам лучше использовать Grand Central Dispatch, хотя:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self getResultSetFromDB:docids];
});
GCD - более новая технология, и она более эффективна с точки зрения затрат памяти и строк кода.
Обновленный с подсказкой для Криса Ноле, который предложил изменение, которое сделает вышеуказанный код более простым и не отставает от последних примеров кода GCD от Apple.
Ответ 2
Ну, это довольно легко на самом деле с GCD. Типичный рабочий процесс будет выглядеть примерно так:
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;
});
});
Подробнее о GCD вы можете посмотреть в документации Apple здесь
Ответ 3
Включите NSZombieEnabled, чтобы узнать, какой объект освобождается и затем доступен.
Затем проверьте, имеет ли значение getResultSetFromDB:
что-то подобное. Также проверьте, есть ли у docids
что-то внутри и если оно сохраняется.
Таким образом, вы можете быть уверены, что нет ничего плохого.
Ответ 4
Библиотека sqlite по умолчанию, поставляемая с iOS, не скомпилирована с использованием макроса SQLITE_THREADSAFE. Это может быть причиной сбоя вашего кода.
Ответ 5
Свифт 2.x ответ:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
self.getResultSetFromDB(docids)
}