Фонова нитка запуску iOS


117

У мене на пристрої iOS невеликий sqlitedb. Коли користувач натискає кнопку, я отримую дані з sqlite і показую їх користувачеві.

Цю частину отримання, яку я хочу зробити у фоновому потоці (щоб не блокувати основний потік інтерфейсу). Я роблю це так -

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

Після отримання & трохи обробки, мені потрібно оновити інтерфейс користувача. Але оскільки (як хороша практика) нам не слід проводити оновлення інтерфейсу користувача з фонових потоків. Я називаю selectorна мейнтеді так -

[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збережено.
Рог

так, docidsє retain. Я поставив це .hяк@property (nonatomic, retain) NSMutableArray *docids;
Шрікар Аппалараджу

Не застосовуйте префіксальні методи за допомогою get; це просто повинно бутиresultSetFromDB:
bbum

Відповіді:


270

Якщо ви використовуєте performSelectorInBackground:withObject:для нерестування нової нитки, то виконаний селектор відповідає за налаштування пулу автоматичного випуску нової нитки, запуску циклу та інших деталей конфігурації - див. "Використання NSObject для нерестування нитки" в Посібнику програмування Apple Threading. .

Можливо, вам буде краще використовувати Grand Central Dispatch , хоча:

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

GCD - це новіша технологія і є більш ефективною з точки зору накладних витрат на пам'ять та рядків коду.


Оновлення з капелюхом наконечником для Кріса Нолет , який запропонував зміни , що робить цей код простіше і зберігає з останніми прикладами НСД коду Apple.


круто! не знав цього. Чи стосується це [NSThread detachNewThreadSelector:@selector....також?
Шрікар Аппалараджу

Так. За документами 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];
теми та якнайменше,

Ви ввімкнули те, що я вам сказав?
Nicolas S

Поставте крапку в цьому рядку: SpotMain * дзеркало = [[SpotMain alloc] init]; і скажи мені, якщо його удар і, якщо tehn, яка лінія вибивається. Увімкніть зомбі, будь ласка, щоб ми могли отримати чіткий журнал помилок.
Nicolas S

так, я включив зомбі. Я отримую це - `2011-08-14 12: 49: 42.697 FLO [16211: 707] *** - [Реліз FMResultSet]: повідомлення, надіслане до розміщеного екземпляра 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 * ... ', він виходить з ладу незабаром після введення фонової нитки ...
Srikar Appalaraju

2

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


2

Відповідь Swift 2.x:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.