iOS: различное поведение addSubview между iOS 4.3 и 5.0 - PullRequest
29 голосов
/ 20 октября 2011

во время кодирования в iOS 4.3 ранее я обнаружил, что при добавлении представления контроллера представления в другое представление с [superview addSubView:controller.view] экземпляр контроллера не получит сообщение -viewWillAppear/viewDidAppear, чем я обнаружил ту же проблему в каком-то потоке при переполнении стека. После этого я вручную вызываю -viewWillAppear/-viewDidAppear по мере необходимости.

, но после обновления до iOS 5.0 произошло резкое поведение UIView. Наконец, я обнаружил, что в iOS 5, [superview addSubView:controller.view], автоматически отправит сообщение -viewWillAppear/-viewDidAppear экземпляру контроллера, плюс мои ручные вызовы, есть два дублированных сообщения каждый раз, когда контроллер выполняет свое поведение.

и я также обнаружил похожую проблему: iOS 5: -viewWillAppear не вызывается после закрытия модального режима в iPad

Теперь проблема в том, что после поиска в документах Apple я не нашел ни одного явного документа для diff по этим вопросам. Мне даже интересно, является ли это гарантированным поведением жизненного цикла представления в iOS 5.0.

Кто-нибудь исправляет подобные проблемы или находит некоторые рекомендации по поводу этих различий? потому что я хочу запустить свое приложение как в 4.x & 5.x iOS.

Ответы [ 7 ]

28 голосов
/ 09 ноября 2011

В iOS 4 вам приходилось вручную вызывать -viewWillAppear, -viewWillDisappear и т. Д. При добавлении или удалении представления из иерархии представлений.Они вызываются автоматически в iOS 5, если представление добавляется или удаляется из иерархии window .К счастью, в iOS 5 есть метод в UIViewController, который вы можете переопределить, чтобы вернуть поведение к тому, как оно работало с iOS 4. Просто добавьте это в ваш UIViewController:

-(BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
   return NO;
}

Это, вероятно,самое простое решение, если вы поддерживаете iOS 4 и iOS 5. После того, как вы откажетесь от поддержки iOS 4, вы можете подумать о том, чтобы изменить свой код, чтобы использовать более новый подход при смене представлений.

Редактировать 5 февраля2012

Очевидно, что для этой функции требуется, чтобы дочерний контроллер вида был добавлен в контроллер основного вида с помощью метода addChildViewController:.Этот метод не существует в iOS4, поэтому вам нужно сделать что-то вроде этого:

  if ([self respondsToSelector:@selector(addChildViewController:)] ) {
     [self addChildViewController:childViewController];
  }

Спасибо всем, кто исправил меня в этом.

9 голосов
/ 21 октября 2011

Возможно, это не тот ответ, который вы хотите, но у меня была такая же проблема.

В моем случае, когда я добавил представление контроллера представления в представление другого контроллера представления как подпредставление, подпредставление было получено viewWillAppear только в iOS 5.0, а не в iOS 4.X.

Итак, я добавил неприятное состояние.

[self.view addSubview:self.viewController.view];
if ([[[UIDevice currentDevice] systemVersion] compare:@"5.0"] == NSOrderedAscending) {
    [self.viewController viewWillAppear:animated];
}

Начиная с iOS 5.0, Apple предоставляет способ реализации пользовательских контроллеров контейнерных представлений, таких как UINavigationController или UITabController . Я думаю, что это изменение влияет, когда вызывается viewWillAppear.

Эта проблема может быть решена, если мы используем -[UIViewController addChildViewController:].

5 голосов
/ 27 января 2012

Ответы выше слегка неполные.Предположим, у вас есть 2 контроллера представления, ControllerA и ControllerB.

ControllerA.view уже добавлен в окно (это родитель), и вы хотите добавить ControllerB.view как подпредставление ControllerA.

Если вы сначала не добавите ControllerB в качестве дочернего элемента ControllerA, то AutomaticForwardAppearanceAndRotationMethodsToChildViewControllers будет игнорироваться, а iOS5 по-прежнему будет вызываться, т. Е. Вы будете вызывать обратные вызовы контроллера представления дважды.

Пример в ControllerA:

- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
    return NO;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.controllerB = [[ControllerB alloc] initWithNibName:@"ControllerB" bundle:nil];

    [self.view addSubview:self.controllerB.view];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.controllerB viewWillAppear:animated];
}

В ControllerB NSLogging in viewWillAppear:

- (void)viewWillAppear:(BOOL)animated
{
    NSLog("@ControllerB will appear");
}

Это приведет к тому, что iOS5 отобразит только это сообщение NSLog только дважды.т.е. вы автоматически ForwardAppearanceAndRotationMethodsToChildViewControllers были проигнорированы.

Чтобы исправить это, вам нужно добавить controllerB как дочерний элемент контроллера a.

Назад в класс ControllerA:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.controllerB = [[ControllerB alloc] initWithNibName:@"ControllerB" bundle:nil];
    if ([self respondsToSelector:@selector(addChildViewController:)])
        [self addChildViewController:self.controllerB];

    [self.view addSubview:self.controllerB.view];
}

Теперь это будет работать, как и ожидалось, как в iOS4, так и в iOS5, не прибегая к ужасному взлому проверки строк версии iOS, но вместо этого проверяя, доступна ли нужная нам функция.

Надеюсь, это поможет.

2 голосов
/ 25 октября 2011

Это поведение iOS5:viewWillAppear, viewDidAppear, ... выполняются автоматически после addSubView: для iOS5.Поэтому для iOS5 нет необходимости выполнять вручную эти методы, как для iOS <5.0.Исправление может быть:</p>

if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) {
...execute viewWillAppear or other
}
0 голосов
/ 27 июля 2012

После просмотра всех доказательств, я думаю, что лучше всего НЕ использовать viewDidAppear и т. Д. Для представлений, которые подвержены этой ошибке ios 4 / ios 5 Вместо этого создайте собственный класс (например, viewDidAppearCustom) и вызовите его самостоятельно. таким образом, вы можете гарантировать, что яблоко не изменит sdk снова и не испортит вас. Здесь есть отличный блог, освещающий эту проблему:

http://gamesfromwithin.com/view-controller-notification-changes-on-ios5

0 голосов
/ 25 октября 2011

view{Will,Did}Appear, view{Will,Did}Disappear - это функции Контроллеры вида , а не виды. Эти функции вызываются предоставленными SDK контроллерами представления, которые должны управлять другими контроллерами представления, например UITabBarController, UINavigationBarController.

Если вы сами управляете контроллерами подвидов, вы должны вызывать их явно (и в правильном порядке - хотя для этого должна быть очень веская причина). Модальное представление, не получающее эти вызовы при отклонении модального представления, просто потому, что нет никого, кто бы мог его вызвать. Инкапсулируйте корневой контроллер вида в UINavigationController (и, если хотите, скройте панель навигации), а затем откройте модальный контроллер вида. При его увольнении, или поп, будет вызван viewWillAppear.

0 голосов
/ 20 октября 2011

С помощью этого метода вы знаете, какое из них вы используете, и ставите условие, если оно меньше 5,0 или другое

[[UIDevice currentDevice] systemVersion]

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...