Вопрос:

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

iphone ios cocoa-touch

96093 просмотра

25 ответа

579 Репутация автора

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

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

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

Документы Apple заявляют:

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

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

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

Автор: chzk Источник Размещён: 25.09.2008 01:52

Ответы (25)


5 плюса

3246 Репутация автора

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

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

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

Автор: Josh Gagnon Размещён: 25.09.2008 07:24

29 плюса

19945 Репутация автора

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

[myViewController viewWillAppear:NO];

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

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

Автор: lajos Размещён: 28.09.2008 01:20

1 плюс

34215 Репутация автора

Я не уверен на 100% в этом, но я думаю, что добавление представления в иерархию представлений напрямую означает обращение -addSubview:к представлению контроллера представления (например, [viewController.view addSubview:anotherViewController.view]) вместо помещения нового контроллера представления в стек контроллера навигации.

Автор: Martin Gordon Размещён: 07.10.2008 03:51

53 плюса

8171 Репутация автора

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

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

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:
Автор: mmalc Размещён: 17.10.2008 04:35

1 плюс

0 Репутация автора

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

Автор: winston Размещён: 25.05.2009 06:05

8 плюса

111 Репутация автора

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

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

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

[super viewWillAppear:animated];

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

В документации сказано:

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

Автор: Antoine Размещён: 13.01.2010 02:46

1 плюс

17117 Репутация автора

Я думаю, что они имеют в виду «напрямую», подключая вещи точно так же, как это делает шаблон xcode «Navigation Application», который устанавливает UINavigationController в качестве единственного подпредставления UIWindow приложения.

Использование этого шаблона - единственный способ, с помощью которого я смог получить методы Will / Did / Appear / Disappear, вызываемые для объекта ViewControllers, после нажатия / выталкивания этих контроллеров в UINavigationController. Ни одно из других решений в ответах здесь не работало для меня, включая реализацию их в RootController и передачу их через (дочерний) NavigationController. Эти функции (будут / делались / появляются / исчезают) вызывались в моем RootController только при отображении / скрытии ВК высшего уровня, моих «логинов» и навигационных ВК, а не суб-ВК в контроллере навигации, поэтому у меня не было возможности «передать их» в Nav VC.

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

Кроме того, принципиально важно заставить его работать после того, как я сегодня часами бьюсь об эту проблему. Будем весьма благодарны за любые фрагменты рабочего кода, использующие пользовательский RootController и дочерний VC для навигации.

Автор: Bogatyr Размещён: 15.06.2010 03:50

1 плюс

11 Репутация автора

На случай, если это кому-нибудь поможет. У меня была похожая проблема, когда мой ViewWillAppearне стреляет UITableViewController. После долгих тренировок я понял, что проблема была в том, UINavigationControllerчто управляющий мой UITableViewне в корневом представлении. Как только я это исправлю, теперь он работает как чемпион.

Автор: Andrew Размещён: 19.11.2010 08:18

3 плюса

5769 Репутация автора

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

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

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

Автор: AndrewS Размещён: 22.11.2010 03:21

1 плюс

4245 Репутация автора

[self.navigationController setDelegate:self];

Установите делегата на корневой контроллер представления.

Автор: Gaurav Размещён: 23.11.2010 01:36

3 плюса

7061 Репутация автора

Поскольку никакого ответа не принято, и люди (как и я) приземляются здесь, я даю свой вариант. Хотя я не уверен, что это была первоначальная проблема. Когда контроллер навигации добавляется как подпредставление к другому представлению, вы должны сами вызывать методы 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

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

альтернативный текст

Автор: hol Размещён: 04.12.2010 08:53

18 плюса

26949 Репутация автора

Я наконец нашел решение для этого, что работает!

UINavigationControllerDelegate

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

Автор: Chris Размещён: 22.12.2010 10:38

4 плюса

2375 Репутация автора

Во-первых, панель вкладок должна быть на корневом уровне, то есть добавлена ​​в окно, как указано в документации 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это было на уровне окна, и документы, кажется, подтверждают это.

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

Автор: Sam Размещён: 26.07.2011 05:10

-3 плюса

108 Репутация автора

В любое время у вас должен быть активен только 1 UIViewController. Любые подпредставления, которыми вы хотите манипулировать, должны быть именно такими - subVIEWS - т.е. UIView.

Я использую простую технику для управления своей иерархией представлений, и мне еще не приходилось сталкиваться с проблемой, так как я начал что-то делать таким образом. Есть 2 ключевых момента:

  • один UIViewController должен использоваться для управления "стоимостью экрана" вашего приложения
  • используйте UINavigationController для смены представлений

Что я имею в виду под «стоимостью экрана»? Это немного расплывчато, но обычно это функция или раздел вашего приложения. Если у вас есть несколько экранов с одним и тем же фоновым изображением, но с разными оверлеями / всплывающими окнами и т. Д., Это должен быть 1 контроллер представления и несколько дочерних представлений. Вы никогда не должны работать с двумя контроллерами представления. Обратите внимание, что вы все еще можете создать экземпляр UIView в одном контроллере представления и добавить его в качестве подпредставления другого контроллера представления, если вы хотите, чтобы определенные области экрана отображались в нескольких контроллерах представления.

Что касается UINavigationController - это ваш лучший друг! Отключите панель навигации и укажите «Нет» для анимации, и у вас есть отличный способ переключения экранов по требованию. Вы можете выдвигать и выдвигать контроллеры представления, если они находятся в иерархии, или вы можете подготовить массив контроллеров представления (включая массив, содержащий один VC) и установить его в качестве стека представления, используя setViewControllers. Это дает вам полную свободу менять ВК, в то же время получая все преимущества работы в рамках ожидаемой модели Apple и обеспечения надлежащего запуска всех событий и т. Д.

Вот что я делаю каждый раз, когда запускаю приложение:

  • начать с оконного приложения
  • добавить UINavigationController в качестве rootViewController окна
  • добавить все, что я хочу, чтобы мой первый UIViewController был rootViewController контроллера nav

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

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

Автор: Nigel Flack Размещён: 17.09.2011 11:05

-2 плюса

12 Репутация автора

Я не уверен, что это та же проблема, которую я решил.
В некоторых случаях метод не выполняется обычным способом, таким как «[self methodOne]».

Пытаться

- (void)viewWillAppear:(BOOL)animated
{
    [self performSelector:@selector(methodOne) 
           withObject:nil afterDelay:0];
}
Автор: Sean Размещён: 16.11.2011 07:35

2 плюса

706 Репутация автора

Я использую этот код для контроллеров push и pop view:

От себя:

[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];

поп:

[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];

.. и у меня работает нормально.

Автор: Arash Zeinoddini Размещён: 22.06.2012 07:57

1 плюс

2185 Репутация автора

У меня просто была эта проблема, и мне потребовалось 3 полных часа (2 из которых - поиск в Google), чтобы решить ее.

Помогло то, что нужно было просто удалить приложение с устройства / симулятора, очистить, а затем снова запустить .

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

Автор: Finn Gaida Размещён: 21.09.2013 06:18

2 плюса

5522 Репутация автора

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

Автор: giuseppe Размещён: 05.12.2013 02:05

3 плюса

982 Репутация автора

Правильный способ сделать это - использовать 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];
}
Автор: Hari Kunwar Размещён: 28.07.2015 04:47

0 плюса

1618 Репутация автора

В моем случае проблема была с пользовательской анимацией перехода. Когда набор modalPresentationStyle = .custom viewWillAppearне называется

в пользовательском классе анимация перехода необходимо вызвать методы: beginAppearanceTransitionиendAppearanceTransition

Автор: ober Размещён: 23.10.2018 08:23

1 плюс

1791 Репутация автора

Для Свифта. Сначала создайте протокол для вызова того, что вы хотели вызвать в viewWillAppear

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

Во-вторых, создать класс

class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
    if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
        updatedCntllr.myViewWillAppear()
    }
}

}

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

Автор: Vadim Motorine Размещён: 20.12.2018 06:03

0 плюса

180 Репутация автора

В моем случае это была просто странная ошибка в эмуляторе ios 12.1. Исчез после запуска на реальном устройстве.

Автор: coldembrace Размещён: 29.01.2019 07:25

0 плюса

372 Репутация автора

Я создал класс, который решает эту проблему. Просто установите его в качестве делегата вашего контроллера навигации и внедрите простой один или два метода в вашем контроллере представления - которые будут вызываться, когда представление будет показано или было показано через NavigationController

Вот ГИСТ, показывающий код

Автор: GregJaskiewicz Размещён: 21.02.2019 10:31

0 плюса

463 Репутация автора

ViewWillAppear - это метод переопределения класса UIViewController, поэтому добавление subView не вызовет viewWillAppear, но при представлении push, pop, show, setFront или popToRootViewController из viewController будет вызван viewWillAppear для представленного viewController.

Автор: Abu Ul Hassan Размещён: 21.02.2019 10:52

0 плюса

4000 Репутация автора

Спасибо iOS 13.

ViewWillDisappear, ViewDidDisappear, ViewWillAppearИ ViewDidAppearне будет вызван на контроллере представления Предъявление КСН 13 , который использует новый модальное представление , которое не покрывает весь экран.

Кредиты собираются на Арек Холко . Он действительно спас мой день.

введите описание изображения здесь

Автор: BilalReffas Размещён: 14.06.2019 01:54
32x32