UIActivityIndicatorView никогда не анимирует

У меня есть класс PhotoViewController с классом @property UIActivityIndicatorView* spinner. FlickrPhotoViewController — это подкласс PhotoViewController, который загружает фото с Flickr и сообщает счетчику, когда начинать и останавливать анимацию. 'updatePhoto' вызывается каждый раз, когда контроллеру представления передается фотография Flickr:

- (void)updatePhoto { // Download photo and set it
    NSLog("updatePhoto called");
    if (self.spinner) NSLog(@"Spinner exists in updatePhoto");
    dispatch_queue_t downloadQueue = dispatch_queue_create("downloader",
                                                           NULL);
    [self.spinner startAnimating];

    dispatch_async(downloadQueue, ^{
        // Download the photo
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.spinner stopAnimating];
            // Set the photo in the UI
            }
        });
    });
}

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

Вы заметите, что в начале updatePhoto я печатаю сообщение, если UIActivityIndicatorView существует. Я поместил аналогичное утверждение в awakeFromNib, viewDidLoad и viewWillAppear. Когда я запускаю его, это точный результат, который я получаю:

2013-01-31 21:30:55.211 FlickrExplorer[1878:c07] updatePhoto called
2013-01-31 21:30:55.222 FlickrExplorer[1878:c07] Spinner exists in viewDidLoad
2013-01-31 21:30:55.223 FlickrExplorer[1878:c07] Spinner exists in viewWillAppear

Почему spinner не существует в awakeFromNib? Документы указывают, что «когда объект получает сообщение awakeFromNib, для него гарантированно уже установлены все его выходы и подключения к действиям». Можно ли подключить IBOutlet без существования объекта, к которому он подключается? В этом случае можно ли подключить spinner IBOutlet к раскадровке без выделения spinner?

Помимо этого, я переопределил геттер для spinner, чтобы он создавал экземпляр, если он не существует. В результате вывод на печать теперь выглядит так:

2013-01-31 21:48:45.646 FlickrExplorer[2222:c07] Spinner exists in awakeFromNib
2013-01-31 21:48:45.647 FlickrExplorer[2222:c07] updatePhoto called
2013-01-31 21:48:45.647 FlickrExplorer[2222:c07] Spinner exists in updatePhoto
2013-01-31 21:48:45.649 FlickrExplorer[2222:c07] Spinner exists in viewDidLoad
2013-01-31 21:48:45.650 FlickrExplorer[2222:c07] Spinner exists in viewWillAppear

Это то, что я ожидал увидеть раньше. Тем не менее, я все еще не получаю никакой анимации.

Возможные проблемы, которые я исключил:

Все эти три возможности исключаются тем фактом, что добавление [self.spinner startAnimating]; в viewWillAppear позволяет успешно анимировать его на протяжении всего процесса загрузки.

Вы можете загрузить этот проект, если хотите. Просто перейдите на любой экран, который пытается отобразить большую фотографию, и вы увидите, что счетчик не появляется. У этого проекта много проблем, но сейчас я сосредоточусь на этой.

Редактировать 1:

  • Я добавил отсутствующие зависимости проекта от Git, поэтому теперь проект будет компилироваться для вас.

Редактировать 2 (2 февраля 2013 г.):

  • Я вижу эту проблему только на iPhone, когда метод updatePhoto вызывается из-за того, что prepareForSegue другого контроллера представления устанавливает фотографию в файле FlickrPhotoViewController. Возможно ли, что это способствует возникновению проблемы?

person Xander Dunn    schedule 31.01.2013    source источник
comment
почему бы вам просто не использовать MBProgressHUD github.com/jdg/MBProgressHUD и уберечь себя от всех этих ActivityIndicator проблем   -  person u.gen    schedule 31.01.2013
comment
Прошло много времени с тех пор, как я читал такой хороший, краткий вопрос с таким количеством исследовательских усилий. +1. И примите от меня совет: не напрягайтесь, используя «дерьмовый» конструктор интерфейсов. Код работает просто отлично.   -  person    schedule 31.01.2013
comment
+1 за полноту вопроса. Побудил меня получить ваш код и просмотреть его. Трудно протестировать, потому что это далеко не компиляция. Я заметил несколько вещей: ваш вид в IB белый, а код, на который вы ссылаетесь в вопросе, вызывается сеттером setPhoto:, который вызывается внешним VC, совсем не ясно, что ваш FlickrPhotoViewController правильно инициализируется до того, как этот материал, связанный с пользовательским интерфейсом, начнет происходить.   -  person danh    schedule 31.01.2013
comment
Еще одна хорошая практика полноты вопроса — свести проблему к минимальной ситуации, которая демонстрирует проблему. например Можете ли вы увидеть, можете ли вы просто запустить счетчик на этом VC всякий раз, когда он появляется?   -  person danh    schedule 31.01.2013
comment
Вы добавили счетчик в качестве подвида? Вы пробовали комментировать stopAnimating? Возможно, он вызывается очень быстро и не дает возможности оживиться. Можете дать пример проекта?   -  person Yariv Nissim    schedule 01.02.2013
comment
@SpaceDust Спасибо за ссылку на этот проект. Для любого реального проекта я, вероятно, буду использовать такую ​​библиотеку. Тем не менее, я в настоящее время новичок, и мне очень хотелось бы выяснить, почему это происходит.   -  person Xander Dunn    schedule 01.02.2013
comment
@danh Спасибо за комплимент. Жаль проект не строится. Я никогда не делаю коммит, если проект не строится, поэтому я не должен включать некоторые зависимости в коммиты проекта. Извини. Я исправлю это, как только доберусь до своего компьютера. Кроме того, как указано в нижней части моего вопроса, я действительно могу запустить счетчик, если я испорчу представление с viewWillAppear.   -  person Xander Dunn    schedule 01.02.2013
comment
@ yar1vn Я не совсем понимаю, как вы хотите добавить его в качестве подвида. Я использую раскадровки, поэтому я ожидаю, что раскадровка позаботится об этом. Комментировать stopAnimating — хорошая идея, но проблема не в этом, поскольку вызов startAnimating из viewWillAppear работает просто отлично, как указано в моем исходном посте. Кроме того, ссылка на исходный проект включена в мой исходный пост.   -  person Xander Dunn    schedule 01.02.2013
comment
Я не могу построить этот проект. Это пропавшие файлы..   -  person Yariv Nissim    schedule 01.02.2013
comment
@ yar1vn Да, извините, другой комментатор указал на это. Это моя ошибка. Я не включил все зависимости в коммиты проекта. Я исправлю это, как только вернусь домой. Я живу в стране третьего мира, и я отвечаю на это сообщение через сеть Edge во время обеденного перерыва. Если у нас будет электричество, когда я вернусь домой, я смогу исправить коммит на GitHub.   -  person Xander Dunn    schedule 01.02.2013
comment
@ H2CO3 Вы упомянули, что Interface Builder дерьмовый. Есть ли у вас ссылки на статьи, объясняющие, почему это так? Это хорошо сработало для меня, и мне кажется, это отличный способ документировать пользовательский интерфейс и удалить много бесполезного кода инициализации.   -  person Xander Dunn    schedule 02.02.2013
comment
Статьи @thoughtadvances? Возможно, мои статьи в будущем :) Это мое личное мнение (т.е. мне оно сильно не нравится, что само по себе не означает, что и другим тоже). Мое рассуждение: 1. Я нахожу его структуру нелогичной и довольно запутанной, вы никогда не можете знать, что с чем связано, какой файл принадлежит какому объекту, даже не какой назначенный инициализатор вызывается (при использовании ваших пользовательских UIView[Controller] подклассов) и т. д. 2 Если приложение разработано с использованием IB, разработчик без IB ни за что не сможет над ним работать. 3. Это заставляет ленивых новичков избегать обучения кодированию пользовательского интерфейса.   -  person    schedule 02.02.2013


Ответы (1)


Попробуйте запустить анимацию uiactivityindictor до того, как вы вызовете метод updatePoto, подобный этому. Tru вызывает этот i вместо вызова UpdatePhoto только для всех:

[self startAnimatingAndThenUpdatePhoto];


-(void)startAnimatingAndThenUpdatePhoto{
 if (self.spinner) NSLog(@"Spinner exists in updatePhoto");
  [self.spinner startAnimating];
 [self performSelector:@selector(updatePhoto) withObject:nil afterDelay:0.01];
}
 - (void)updatePhoto { // Download photo and set it
        NSLog("updatePhoto called");
        dispatch_queue_t downloadQueue = dispatch_queue_create("downloader",
                                                               NULL);

        dispatch_async(downloadQueue, ^{
            // Download the photo
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.spinner stopAnimating];
                // Set the photo in the UI
                }
            });
        });
    }

Не лучший метод в мире, но он сделает свою работу

person Hmeedo    schedule 31.01.2013
comment
Фу! Это сработало! НО ПОЧЕМУ!? Ранее я нашел ответ StackOverflow, предлагающий сделать это наоборот: - (void) updatePhoto { [self performSelector:@selector(startSpinning) withObject:nil afterDelay:0.01]; // Code to update the photo Однако у меня это не сработало. Изменение того, какой метод вызывается через performSelector, действительно работает! Но это ужасное, злое, уродливое решение! Почему это нужно здесь, а не в других местах? Почему в моем коде жестко запрограммировано 0.01!? - person Xander Dunn; 02.02.2013
comment
Я сделал большую ошибку. Вы можете полностью игнорировать мой последний комментарий. Боюсь, эта идея совсем не помогла проблеме. Я протестировал его на iPad после применения этого исправления. Но у меня никогда не было проблем с анимацией спиннера на iPad. Как и раньше, он по-прежнему не работает на iPhone. - person Xander Dunn; 02.02.2013