iPhone viewWillAppear не стреляет - PullRequest
       80

iPhone viewWillAppear не стреляет

114 голосов
/ 25 сентября 2008

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

Если я создам RootViewController и вызову addSubView на этом контроллере, я ожидаю, что добавленные представления будут подключены к событиям viewWillAppear.

Есть ли у кого-нибудь пример сложной программной иерархии представлений, которая успешно получает viewWillAppear событий на каждом уровне?

Состояние документов Apple:

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

Проблема в том, что они не описывают, как это сделать. Что значит «напрямую»? Как вы «косвенно» добавляете представление?

Я довольно новичок в Какао и iPhone, поэтому было бы неплохо, если бы были полезные примеры от Apple, кроме основного хрена Hello World.

Ответы [ 24 ]

53 голосов
/ 17 октября 2008

Если вы используете контроллер навигации и задаете его делегат, то методы представления {Will, Did} {Appear, Disappear} не запускаются.

Вместо этого необходимо использовать методы делегата контроллера навигации:

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:
29 голосов
/ 28 сентября 2008

Я столкнулся с этой же проблемой. Просто отправьте сообщение viewWillAppear вашему контроллеру представления, прежде чем добавить его в подпредставление (Существует один параметр BOOL, который сообщает контроллеру представления, должен ли он быть анимированным, появиться или нет.)

[myViewController viewWillAppear:NO];

Посмотрите на RootViewController.m в примере Metronome.

(Я действительно нашел примеры проектов Apple великолепными. Существует намного больше, чем HelloWorld;)

18 голосов
/ 22 декабря 2010

Я наконец нашел решение для этого, ЧТО РАБОТАЕТ!

UINavigationControllerDelegate

Я думаю, что суть этого в том, чтобы установить делегат вашего элемента управления навигацией для контроллера, в котором он находится, и реализовать UINavigationControllerDelegate, и это два метода. Brilliant! Я так взволнован, что наконец нашел решение!

8 голосов
/ 13 января 2010

У меня просто была такая же проблема. В моем приложении у меня есть 2 контроллера навигации и нажатие на один и тот же контроллер представления в каждом из них работал в одном случае, а не в другом. Я имею в виду, что при нажатии точно такого же контроллера вида в первом UINavigationController вызывался viewWillAppear, но не при нажатии во втором навигационном контроллере.

Тогда я наткнулся на этот пост UINavigationController должен вызывать методы viewWillAppear / viewWillDisappear

И понял, что мой второй навигационный контроллер переопределил viewWillAppear. Скрининг кода показал, что я не звонил

[super viewWillAppear:animated];

Я добавил это, и это сработало!

Документация гласит:

Если вы переопределите этот метод, вы должны вызвать super в какой-то момент вашей реализации.

5 голосов
/ 25 сентября 2008

Я использую навигационный контроллер. Когда я хочу перейти на другой уровень данных или показать свой пользовательский вид, я использую следующее:

[self.navigationController pushViewController:<view> animated:<BOOL>];

Когда я это делаю, у меня срабатывает функция viewWillAppear. Я предполагаю, что это квалифицируется как «косвенный», потому что я сам не вызываю метод addSubView. Я не знаю, применимо ли это на 100% к вашему приложению, так как не могу сказать, используете ли вы навигационный контроллер, но, возможно, это даст подсказку.

4 голосов
/ 26 июля 2011

Во-первых, панель вкладок должна быть на корневом уровне, т.е. добавлена ​​в окно, как указано в документации Apple. Это ключ к правильному поведению.

Во-вторых, вы можете использовать UITabBarDelegate / UINavigationBarDelegate для пересылки уведомлений вручную, но я обнаружил, что для правильной работы всей иерархии вызовов представлений все, что мне нужно было сделать, это вручную позвоните

[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];

и

[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];

.. ТОЛЬКО ОДИН РАЗ перед установкой контроллеров представления на соответствующем контроллере (сразу после выделения). С тех пор он правильно вызывал эти методы на своих дочерних контроллерах представления.

Моя иерархия такая:

window
    UITabBarController (subclass of)
        UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
            UINavigationController (subclass of)
                UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods

Простой вызов упомянутых методов на контроллере tab / nav в первый раз гарантировал, что ВСЕ события были перенаправлены правильно. Это остановило меня от необходимости вызывать их вручную из методов UINavigationBarDelegate / UITabBarControllerDelegate.

Sidenote: Любопытно, что когда это не сработало, приватный метод

- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController 

.., который вы можете видеть из callstack на работающей реализации, обычно вызывает методы viewWill/Did.., но не делал, пока я не выполнил вышеизложенное (даже если он был вызван).

Я думаю, что ОЧЕНЬ важно, что UITabBarController находится на уровне окна, и документы, похоже, подтверждают это.

Надеюсь, что было ясно (иш), рад ответить на дополнительные вопросы.

3 голосов
/ 28 июля 2015

Правильный способ сделать это - использовать API-интерфейс UIViewController.

- (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     UIViewController *viewController = ...;
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
     [viewController didMoveToParentViewController:self];
}
3 голосов
/ 04 декабря 2010

Поскольку никакого ответа не принято, и люди (как и я) приземляются здесь, я даю свой вариант. Хотя я не уверен, что это была первоначальная проблема. Когда контроллер навигации добавляется как подпредставление к другому представлению, вы должны сами вызывать методы viewWillAppear / Dissappear и т. Д., Например:

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [subNavCntlr viewWillAppear:animated];
}

- (void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [subNavCntlr viewWillDisappear:animated];
}

Просто чтобы завершить пример. Этот код появляется в моем ViewController, где я создал и добавил навигационный контроллер в представление, которое я поместил в представление.

- (void)viewDidLoad {

    // This is the root View Controller
    rootTable *rootTableController = [[rootTable alloc]
                 initWithStyle:UITableViewStyleGrouped];

    subNavCntlr = [[UINavigationController alloc]   
                  initWithRootViewController:rootTableController];

    [rootTableController release];

    subNavCntlr.view.frame = subNavContainer.bounds;

    [subNavContainer addSubview:subNavCntlr.view];

    [super viewDidLoad];
}

.h выглядит так

@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
    IBOutlet UIView *subNavContainer;
    UINavigationController *subNavCntlr;
}

@end

В файле пера у меня есть вид, а под этим видом у меня есть метка изображения и контейнер (другой вид), куда я помещаю контроллер. Вот как это выглядит. Мне пришлось кое-что исправить, так как это работало для клиента.

alt text

3 голосов
/ 22 ноября 2010

Представления добавляются "напрямую", вызывая [view addSubview:subview]. Представления добавляются «косвенно» такими методами, как панели вкладок или панели навигации, которые меняют подвиды.

Каждый раз, когда вы звоните [view addSubview:subviewController.view], вам следует звонить [subviewController viewWillAppear:NO] (или ДА в зависимости от вашего случая).

У меня была эта проблема, когда я внедрил свою собственную систему управления корневыми представлениями для подэкрана в игре. Добавление вызова к viewWillAppear вручную вылечило мою проблему.

2 голосов
/ 05 декабря 2013

Очень распространенная ошибка заключается в следующем. У вас есть одно представление, UIView* a, и другое, UIView* b. Вы добавляете b в a как подпредставление. Если вы попытаетесь вызвать viewWillAppear в b, он никогда не будет запущен, потому что это подпредставление

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