Темы и вопросы автозапуска - PullRequest
       38

Темы и вопросы автозапуска

1 голос
/ 17 сентября 2011

Насколько я понимаю, существует несколько способов отправки задач для выполнения в потоках. Наиболее распространенные из них, которые я использую:

1) executeSelector: withObject: afterDelay:

2) executeSelectorOnMainThread: withObject: waitUntilDone:

3) executeSelectorInBackground: withObject:

4) [NSThread detachNewThreadSelector: toTarget: withObject:]

Мой первый вопрос: в чем разница между 1) и 2), помимо очевидных различий в параметрах? На самом ли деле они оба работают в главном потоке (чей пул автоматического выпуска был автоматически создан в main.m)? Я только что прочитал из чьего-то поста в Stackoverflow, что метод 1) фактически работает в новом потоке, и поэтому для его метода селектора должен быть создан пул автоматического выпуска. Это правильно? Я много использовал 1), в основном для того, чтобы воспользоваться параметром задержки, но я никогда не создавал пул автоматического выпуска для них. Ничего катастрофического не произошло.

Далее 3) и 4) оба выполняют задачи в отдельном потоке. Я слышал, что пользовательский интерфейс никогда не должен выполняться в этих потоках, но я не совсем понимаю, что такое UI. Я пытался написать код, который в основном воспроизводил бы повторяющуюся анимацию загрузки, пока табличное представление запускается модально из контроллера навигации. Затем анимация останавливается в методе viewDidLoad контроллера таблицы. Сначала я просто вставил код, чтобы запустить анимацию над строками кода, которые запускают модальное представление. Произошло то, что анимация никогда не воспроизводилась.

[[self loadingView] playAnimation];

SettingsViewController *menus = [[SettingsViewController alloc] initWithNibName:@"SettingsViewController" bundle:nil];

MyNavigationController *navController = [[MyNavigationController alloc] initWithRootViewController:menus];

[menus setParent:navController];
[navController setDelegate:self];
menus.mainViewController = self;

[self presentModalViewController:navController animated:YES];
[navController release];
[menus release];

Затем я попробовал следующее, и это сработало ...

[NSThread detachNewThreadSelector:@selector(settingsOpeningThread) toTarget:self withObject:nil];
[[self loadingView] playAnimation];



- (void) settingsOpeningThread {

NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];

SettingsViewController *menus = [[SettingsViewController alloc]   initWithNibName:@"SettingsViewController" bundle:nil];

MyNavigationController *navController = [[MyNavigationController alloc] initWithRootViewController:menus];

[menus setParent:navController];
[navController setDelegate:self];
menus.mainViewController = self;

[self presentModalViewController:navController animated:YES];
[navController release];
[menus release];

[apool release];

}

Анимация продолжает воспроизводиться до полного запуска представления SettingsViewController. Но стоит ли запускать модальные представления, подобные этому, как «пользовательский интерфейс» и его следует избегать? Также я получаю некоторые странные ошибки утечки памяти в Инструментах каждый раз, когда запускается модальное представление. Но это из одной из "системных библиотек", о которой мне сказали, что ее очень трудно отлаживать. Что может быть не так?

Извините за смущающе длинный пост. Любая помощь будет оценена!

1 Ответ

1 голос
/ 10 октября 2011

(1) планирует задачу для текущего цикла выполнения .На очень высоком уровне UIKit-приложение выглядит как

while(true) {
  update UI
  run all tasks that were scheduled last time through the loop
}

. Вот почему вы не видели обновленный пользовательский интерфейс с первой попытки;вызов playAnimation планирует обновление пользовательского интерфейса на следующей итерации цикла выполнения, но он никогда не будет достигнут до тех пор, пока код, который следует за ним, не будет завершен.

Обратите внимание, что performSelector:withObject:afterDelay не не запускает указанный код в отдельном потоке.

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

И да, ваш код слегка выделен жирным шрифтом.Я бы предложил сделать что-то вроде:

[[self loadingView] playAnimation];
[self performSelector:@selector(loadTable) withObject:nil afterDelay:0]

, где фактический код для загрузки таблицы находится в loadTable.Это означает, что при запуске runloop ваш пользовательский интерфейс будет обновлен, анимация начнет воспроизводиться, затем будет вызван метод loadTable и выполнит свою работу.

Это все равно не будет работатьоднако если анимация требует вмешательства основного потока для выполнения.То есть, если код для загрузки таблицы останавливает основной поток, ваша анимация также может зависнуть.В действительности нет другого пути, кроме как выполнить долгосрочное задание в отдельном потоке (который может или не может использовать performSelector:onMainThread:waitUntilDone для планирования обновлений пользовательского интерфейса в главном потоке).

Если вам все равномногое о самой анимации, вы можете найти что-то вроде https://github.com/samvermette/SVProgressHUD полезным.

...