iOS запускает фоновый поток

117

У меня на устройстве iOS есть небольшой sqlitedb. Когда пользователь нажимает кнопку, я извлекаю данные из sqlite и показываю их пользователю.

Эту часть выборки я хочу сделать в фоновом потоке (чтобы не блокировать основной поток пользовательского интерфейса). Я так делаю -

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

После получения и небольшой обработки мне нужно обновить пользовательский интерфейс. Но поскольку (как хорошая практика) мы не должны выполнять обновление пользовательского интерфейса из фоновых потоков. Я называю это selectorна mainthread так -

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

Но мое приложение вылетает на первом этапе. т.е. запуск фонового потока. Разве это не способ запустить фоновые потоки в iOS?

ОБНОВЛЕНИЕ 1: после того, как [self performSelectorInBackground....я получу эту трассировку стека, никакой информации о чем-либо -

введите описание изображения здесь

ОБНОВЛЕНИЕ 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;
}
Шрикар Аппалараджу
источник
Какой журнал ошибок / сбоев вы получаете?
jtbandes
Пожалуйста, смотрите мои обновления ...
Srikar Appalaraju
Не могли бы вы показать метод, который вы вызываете, в фоновом режиме? И убедитесь, что объект docidsсохранился.
Rog
да, docidsесть retain. Я вставил это .hкак@property (nonatomic, retain) NSMutableArray *docids;
Srikar Appalaraju
Не добавляйте к методам префикс get; это должно быть простоresultSetFromDB:
bbum

Ответы:

270

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

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

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

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


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

Скотт Форбс
источник
прохладный! не знал этого. Применимо ли это [NSThread detachNewThreadSelector:@selector....также к?
Srikar Appalaraju,
Да. Согласно документации Apple, вызов performSelectorInBackground:withObject:«аналогичен вызову detachNewThreadSelector:toTarget:withObject:метода NSThreadс текущим объектом, селектором и объектом параметра в качестве параметров».
Скотт Форбс,
Есть ли разница между (unsigned long)NULLи 0в этом вопросе?
Sti
4
@Sti из Apple Dev Docs : Примечание. Второй аргумент функции dispatch_get_global_queue зарезервирован для будущего расширения. На данный момент вы всегда должны передавать этому аргументу 0.
Джавад Аль Шейх
Должен ли я затем использовать performSelectorOnMainThread для обновления пользовательского интерфейса с результатами операции или существует более последовательный способ обновления пользовательского интерфейса с помощью GCD?
Илья Денисов
9

Что ж, с 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

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

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

Николас С
источник
Скопируйте используемую вами строку, которая плавно работает в основном потоке.
Nicolas S
Я использую это из основного потока, и, по крайней мере, он попадает в этот метод вместо внезапного сбоя -[self getResultSetFromDB:docids];
Srikar Appalaraju
ты активировал то, что я тебе сказал?
Nicolas S
Поместите точку останова в эту строку: SpotMain * mirror = [[SpotMain alloc] init]; и скажите мне, ударил ли он и, если техн, какая линия выйдет из строя. Включите зомби, чтобы мы могли получить четкий журнал ошибок.
Nicolas S
да, я включил зомби. Я получаю это - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [FMResultSet release]: сообщение, отправленное в освобожденный экземпляр 0x2bff80 2011-08-14 12:49: 42.697 FLO [16211: 1607] *** __NSAutoreleaseNoPool (): объект 0x2c0cc0 класса __NSCFData автоматически выпущен без пула - просто утечка . Also when I try to call this method from background thread I do not reach SpotMain * mirror ... `, он вылетает вскоре после входа в фоновый поток ...
Srikar Appalaraju,
2

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

Mugunth
источник
2

Ответ Swift 2.x:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
Crashalot
источник