Начальная тема 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)
    }