Xcode6, iOS8 и (недействительные)layoutSubviews

#uilabel #autolayout #ios8 #xcode6 #layoutsubviews

#uilabel #автозапуск #ios8 #xcode6 #layoutsubviews

Вопрос:

У меня есть пользовательский UILabel, который отлично работает на iOS6 и iOS7. Но в iOS8 метод layoutSubviews этой метки (void) никогда не вызывается. Я создаю эту метку с помощью initWithFrame, поэтому этот метод должен быть вызван — и он вызывается в других версиях iOS. Что происходит с системой автозапуска в iOS8?

Комментарии:

1. Вы когда-нибудь понимали это?

2. Проблема еще хуже, так как также при использовании autolayout для subview он не получает layoutet.

3. Я создал пример проекта, показывающий проблему. Запустите на iOS 7 и 8, чтобы увидеть разницу. github.com/fabb/LabelTest

4. Я также сталкиваюсь с такой же проблемой. Вы получили какой-либо ответ на это?

5. Кажется, проблема была исправлена в бета-версии iOS 8.1.

Ответ №1:

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

С iOS 8 до 8.0.2 LayoutSubviews вызовы ненадежны. Они могут не вызываться никогда или (в моем случае) вызываются в цикле.

Даже если вы не должны этого делать, было довольно безопасно размещать материал в layoutSubviews, но с этим ошибочным (?!) поведением это может привести к труднопрослеживаемым ошибкам.

Я не знаю, исправляет ли 8.1 все проблемы, но пройдет некоторое время, пока устройства клиентов не будут запускать 8.1, и теперь они запускают 8.0.2

Комментарии:

1. Я сталкиваюсь с той же проблемой здесь. «layoutSubviews» вызывается в цикле, чтобы охватить пользователей, использующих iOS 8.0.2, есть ли какое-либо исправление для этой ошибки?

2. нет, насколько мне известно, исправления нет. Но вы не должны пытаться поддерживать версии iOS, которые были промежуточными версиями. Если кто-то все еще использует 8.0 или 8.0.2, он может перейти на более новую версию и самостоятельно устранить проблему.

3. Да, это правда. Но, к сожалению, в приложениях мы не можем попросить каждого клиента, подключенного к этой версии, обновить свое устройство. 😉 Ну, я думаю, что я нашел обходной путь. Спасибо за ваш ответ. 🙂

Ответ №2:

У меня была такая же проблема. На самом деле layoutSubviews больше не вызывается для UILabel в iOS8, поскольку Apple не ожидает, что кто-либо использует его в качестве супервизора.

Я использую ReactiveCocoaLayout, поэтому это можно сделать, подписавшись на rcl_frameSignal или rcl_boundsSignal.

-(void)awakeFromNib
{
[ self.rcl_boundsSignal
subscribeNext:
^( NSValue* boundsValue )
{
//layout changed
} ];
}

Или вы можете использовать простой KVO, чтобы узнать, когда фрейм был изменен:

 -(void)dealloc
{
   [ self removeObserver: self forKeyPath: @"layer.bounds" ];
}

-(void)observeValueForKeyPath:( NSString* )keyPath
                     ofObject:( id )object
                       change:( NSDictionary* )change
                      context:( void* )context
{
   if ( [ keyPath isEqualToString: @"layer.bounds" ] )
   {
      //layoutSubviews
   }
   else
   {
      [ super observeValueForKeyPath: keyPath
                      ofObject: object
                        change: change
                       context: context ];
   }
}

-(void)awakeFromNib
{
   [ self addObserver: self
           forKeyPath: @"layer.bounds"
              options: NSKeyValueObservingOptionNew
              context: 0 ];
}
  

Комментарии:

1. Обратите внимание, что UIKit согласно документации НЕ совместим с KVO — даже если он работает в некоторых случаях, он может сломаться в будущем.

Ответ №3:

Ошибка была исправлена Apple в iOS 8.1 (бета-версия).

Комментарии:

1. у вас есть ссылка или что-то для резервного копирования?

2. Могу подтвердить, layoutSubview снова вызывается в бета-версии 8.1

3. Я отправил радар в Apple. И я создал пример проекта: github.com/fabb/LabelTest