IOS: поведение addSubview по-разному между iOS 4.3 и 5.0
при кодировании в 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 я не нашел явного документа для проверки этих проблем. Я даже задаюсь вопросом, является ли это гарантированным показателем жизненного цикла просмотра в iOS 5.0.
Кто-нибудь исправляет подобные проблемы или находит некоторые рекомендации относительно этих различий. Я хочу запустить приложение как в 4.x & 5.x iOS
.
Ответы
Ответ 1
В iOS 4 вам нужно было вручную вызвать -viewWillAppear
, -viewWillDisappear
и т.д. при добавлении или удалении представления из вашей иерархии представлений. Они автоматически вызываются в iOS 5, если представление добавляется или удаляется из иерархии окон. К счастью, у 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];
}
Спасибо всем, кто меня исправил.
Ответ 2
Это может быть не ответ на то, что вы хотите, но у меня была такая же проблема.
В моем случае, когда я добавил представление контроллера представления в другое представление контроллера представления как подвью, subview был получен 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:]
.
Ответ 3
Ответы немного неполные.
Предположим, у вас есть 2 контроллера вида, ControllerA и ControllerB.
ControllerA.view уже добавлен в окно (это родительский элемент), и вы хотите добавить ControllerB.view в качестве подзадачи ControllerA.
Если вы не добавите ControllerB в качестве дочернего элемента ControllerA во-первых, то автоматически игнорируются функции forForAppearanceAndRotationMethodsToChildViewControllers, и вы все равно будете вызываться 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 дважды. т.е. вы автоматически переноситеAppearanceAndRotationMethodsToChildViewControllers игнорируются.
Чтобы исправить это, вам нужно добавить контроллер B в качестве дочернего элемента контроллера 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, но вместо этого проверяет, доступна ли функция, которую мы предоставляем.
Надеюсь, что это поможет.
Ответ 4
Это поведение iOS5:
viewWillAppear, viewDidAppear,... выполняются автоматически после addSubView: для iOS5.
Таким образом, для iOS5 не нужно вручную выполнять эти методы по мере необходимости для iOS < 5.0.
Исправление может быть:
if ([[UIDevice currentDevice].systemVersion doubleValue] < 5.0) {
...execute viewWillAppear or other
}
Ответ 5
С помощью этого метода вы знаете, какое os u использовать и поставить условие, если оно меньше 5.0 или другое
[[UIDevice currentDevice] systemVersion]
Ответ 6
view{Will,Did}Appear
, view{Will,Did}Disappear
- это функции на Контроллерах просмотра, а не на представлениях. Эти функции вызывают контроллеры представлений SDK, которые должны управлять другими контроллерами представлений, например. UITabBarController
, UINavigationBarController
.
Если вы управляете контроллерами суб-представлений самостоятельно, вы должны называть их явно (и в правильном порядке - хотя у вас есть все основания для этого). Модальное представление, не получающее этих призывов об увольнении модального представления, просто потому, что его никто не может назвать. Инкапсулируйте контроллер корневого представления в UINavigationController
(и, если хотите, скройте панель навигации), а затем откройте контроллер модального представления. После его увольнения или поп-музыки viewWillAppear
вызывается.
Ответ 7
После просмотра всех доказательств, я думаю, что лучше всего не использовать viewDidAppear и т.д. для просмотров, которые подвержены этой ошибке ios 4/ios 5. Вместо этого создайте собственный класс (например, viewDidAppearCustom) и вызовите его самостоятельно. таким образом, вы можете гарантировать, что яблоко не изменит sdk и не повредит вам. Здесь есть большой блог, посвященный этой проблеме:
http://gamesfromwithin.com/view-controller-notification-changes-on-ios5