UIActivityIndicator вращается при построении иерархии UIView?

есть ли способ анимировать UIActivityIndicator при построении сложной иерархии UIView? У меня есть сложная иерархия, которую нужно добавить через «addSubview:» в «viewDidLoad» (в основном в проекте раскадровки, но эта сцена создается динамически). Не возясь с GCD, пользовательский интерфейс блокируется до тех пор, пока выполняется инициализация. Помещение инициализации в «dispatch_sync» (показано ниже) не отображает/анимирует индикатор, помещение его в «dispatch_async (dispatch_get_global_queue (0,0),...» приводит к сбою (потому что код UIKit должен выполняться в основной очереди? ) и помещая его в 'dispatch_async (dispatch_get_main_queue(),...', создает тупик (как, я думаю, объявляет Apple).

-(void)viewDidLoad {
    dispatch_sync (dispatch_get_global_queue (0,0), ^{
        // initialization here
        })
}

Итак, в каком направлении двигаться?


person virtualnobi    schedule 02.11.2012    source источник


Ответы (2)


Поместите код в метод и попробуйте

– performSelectorOnMainThread:withObject:waitUntilDone:
– performSelectorOnMainThread:withObject:waitUntilDone:modes:
person sunkehappy    schedule 02.11.2012
comment
Sunkehappy, я тоже пробовал это: поместите инициализацию в новый метод и вызовите его в «viewDidLoad», используя «performSelectorOnMainThread». К сожалению, ничего не меняется: во время инициализации старый экран отображается без счетчика, а после инициализации счетчик кратковременно мигает на экране, прежде чем анимация перехода приводит ко второму экрану. - person virtualnobi; 05.11.2012
comment
Вы говорите, что на экране мигает счетчик. Означает ли это, что подвид успешно добавлен? Может быть, вы попытаетесь выяснить, почему оно «выплескивается», почему оно исчезает? - person sunkehappy; 05.11.2012
comment
Ну, замусорив код точками останова, я вижу, что спиннер добавлен правильно, но он сидит на месте во время всей инициализации ('performSegueWithIdentifier', 'viewDidLoad', 'viewWillAppear' все вызываются правильно). Он начинает вращаться только тогда, когда окончательная анимация перехода (в моем случае переворот) выполняется после выхода из «viewWillAppear». - person virtualnobi; 06.11.2012

Почему бы вам не запустить индикатор активности в viewDidLoad, а затем запланировать инициализацию с помощью PerformSelectorInBackground:

-(void)viewDidLoad {
    [super viewDidLoad];
    [self.activityIndicator startAnimating];
    [self performSelectorInBackground:@selector(finishInitializing) withObject:nil];
}

-(void)finishInitializing {
    // finish resource-intensive setup
    // ...

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.activityIndicator removeFromSuperview];
        // create view hierarchy
        // ...
    });
}

Это позволяет viewDidLoad вернуться, чтобы счетчик мог анимироваться в основном потоке.

person Christopher Pickslay    schedule 03.11.2012
comment
Кристофер, спасибо за ответ. Однако «performSelectorInBackground:» создает новый поток, который, очевидно, больше не является основным потоком (= поток пользовательского интерфейса), и там происходит сбой вызовов UIKit с жалобой на то, что это не правильный поток. - person virtualnobi; 05.11.2012
comment
Да, моя идея заключалась в том, что вы выполняете свою ресурсоемкую работу в этом потоке, а затем завершаете макет пользовательского интерфейса в основном потоке в вызове dispatch_async. Любая медлительность в вашей сложной иерархии UIView почти наверняка связана не с UIKit, а с тем, что вы делаете для подготовки макета. Вам никогда не понадобится индикатор активности только для отображения представлений. - person Christopher Pickslay; 05.11.2012
comment
Что делается при инициализации, так это извлечение объектов из CoreData (представление областей на плане этажа) и соответствующее построение представлений. Я знаю, что могут быть проблемы с производительностью рендеринга в областях (я удалил тень, которую визуальный дизайн хотел сделать достаточно отзывчивой для перетаскивания), но я хотел бы думать, что рендеринг происходит только для видимых областей. - person virtualnobi; 06.11.2012
comment
Вы не должны загружать объекты Core Data в фоновом потоке и передавать их в основной поток. Это может привести к сбоям, которые чрезвычайно трудно воспроизвести. У нас есть аналогичный вариант использования, когда мы загружаем CD в фоновом режиме, копируем необходимые поля в объекты значений, а затем используем эти объекты значений в вызове dispatch_async в основной очереди для рендеринга. Изначально мы передавали объекты CD в основной блок очереди напрямую, и ни разу не сталкивались с сбоями при тестировании, но сообщалось о нескольких сбоях в дикой природе. - person Christopher Pickslay; 07.11.2012
comment
Возможно, вы столкнулись с той же ловушкой, что и я (которая обнаружилась недавно, но не имеет отношения к этой проблеме здесь): CD требует некоторых мер предосторожности, когда задействованы потоки — никогда не перерабатывайте один NSManagedObjectContext в разных потоках и никогда не передавайте NSManagedObjects между потоками. Это написано в руководстве по программированию на компакт-диске под заголовком Concurrency. - person virtualnobi; 23.11.2012