iOS запускает фоновую тему - PullRequest
116 голосов
/ 14 августа 2011

У меня есть маленький 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;
}

Ответы [ 5 ]

269 голосов
/ 14 августа 2011

Если вы используете performSelectorInBackground:withObject: для порождения нового потока, то выполненный селектор отвечает за настройку пула автоматического выпуска нового потока, цикла выполнения и других деталей конфигурации - см. «Использование NSObject для порождения потока» в Apple Руководство по программированию потоков .

Возможно, вам будет лучше использовать Grand Central Dispatch , хотя:

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

GCDЭто более новая технология, которая более эффективна с точки зрения затрат памяти и строк кода.


Обновлен с подсказкой для шляпы Крис Нолет , которыйпредложил изменение, которое упростит приведенный выше код и будет соответствовать последним примерам кода GCD от Apple.

9 голосов
/ 10 августа 2017

Ну, на самом деле это довольно легко с 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 здесь

4 голосов
/ 14 августа 2011

Включить NSZombieEnabled , чтобы узнать, какой объект освобождается и затем доступен. Затем проверьте, имеет ли getResultSetFromDB: какое-либо отношение к этому. Также проверьте, есть ли внутри docids что-нибудь и сохраняется ли оно.

Таким образом, вы можете быть уверены, что все в порядке.

2 голосов
/ 11 мая 2016

Swift 2.x ответ:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
2 голосов
/ 08 июня 2012

Библиотека sqlite по умолчанию, которая поставляется с iOS, не скомпилирована с использованием макроса SQLITE_THREADSAFE. Это может быть причиной сбоя вашего кода.

...