iPhone viewWillAppear没有开火

时间:2008-09-25 01:52:01

标签: iphone ios cocoa-touch

当您没有创建视图层次结构只是时,我已经阅读了很多关于人们viewWillAppear遇到问题的帖子。我的问题是我无法弄清楚这意味着什么。

如果我在该控制器上创建RootViewController并调用addSubView,我希望添加的视图可以连接viewWillAppear个事件。

有没有人有一个复杂的程序化视图层次结构示例,可以在每个级别成功接收viewWillAppear个事件?

Apple的Docs声明:

  

警告:如果属于视图控制器的视图直接添加到视图层次结构中,则视图控制器将不会收到此消息。如果向视图层次结构插入或添加视图,并且它具有视图控制器,则应直接向关联的视图控制器发送此消息。未能发送视图控制器此消息将阻止显示任何关联的动画。

问题是他们没有描述如何做到这一点。 “直接”是什么意思?你如何“间接”添加一个视图?

我对Cocoa和iPhone相当陌生,所以如果除了基本的Hello World垃圾之外还有来自Apple的有用示例,那将会很不错。

27 个答案:

答案 0 :(得分:53)

如果您使用导航控制器并设置其委托,则不会调用视图{Will,Did} {Appear,Disappear}方法。

您需要使用导航控制器委托方法:

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:

答案 1 :(得分:29)

我遇到了同样的问题。只需将viewWillAppear消息发送到视图控制器,然后再将其添加为子视图。 (有一个BOOL参数告诉视图控制器它是否被动画显示。)

[myViewController viewWillAppear:NO];

在Metronome示例中查看RootViewController.m。

(我实际上发现Apple的示例项目非常棒。比HelloWorld更多;)

答案 2 :(得分:18)

我终于找到了这个工作的解决方案!

UINavigationControllerDelegate

我认为它的要点是将导航控件的委托设置为它所在的viewcontroller,并实现UINavigationControllerDelegate,这是两种方法。辉煌!我很兴奋,我终于找到了解决方案!

答案 3 :(得分:8)

我遇到了同样的问题。在我的应用程序中,我有2个导航控制器,并推动相同的视图控制器在每个工作在一个案例而不是在另一个案件。我的意思是当在第一个UINavigationController中推送完全相同的视图控制器时,viewWillAppear被调用但在第二个导航控制器中被推送时没有。

然后我发现了这篇文章UINavigationController should call viewWillAppear/viewWillDisappear methods

并意识到我的第二个导航控制器确实重新定义了viewWillAppear。筛选代码显示我没有打电话

[super viewWillAppear:animated];

我添加它并且它有效!

文档说:

  

如果覆盖此方法,则必须在实施中的某个时刻调用super。

答案 4 :(得分:5)

我一直在使用导航控制器。当我想要下降到另一个级别的数据或显示我的自定义视图时,我使用以下内容:

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

当我这样做时,我确实要启动viewWillAppear功能。我认为这有资格作为“间接”,因为我自己并没有调用实际的addSubView方法。我不知道这是否100%适用于您的应用程序,因为我无法判断您是否使用导航控制器,但它可能会提供线索。

答案 5 :(得分:4)

首先,标签栏应位于根级别,即添加到窗口,如Apple文档中所述。这是正确行为的关键。

其次,你可以使用UITabBarDelegate / UINavigationBarDelegate手动转发通知,但我发现要让整个视图调用层次结构正常工作,所有我必须做的是手动调用

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

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

..在相应控制器上设置视图控制器之前(分配后立即)ONCE。从那时起,它在其子视图控制器上正确调用了这些方法。

我的层次结构是这样的:

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

首次在选项卡/导航控制器上调用上述方法可确保所有事件都正确转发。它阻止了我需要从UINavigationBarDelegate / UITabBarControllerDelegate方法手动调用它们。

旁注: 奇怪的是,当它不起作用时,私有方法

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

..你可以从工作实现的callstack中看到,通常调用viewWill/Did..方法,但直到我执行上述操作(即使它已被调用)。

我认为UITabBarController处于窗口级别非常重要,文档似乎支持这一点。

希望很清楚(ish),很乐意回答进一步的问题。

答案 6 :(得分:3)

Correct way to do this is using UIViewController containment api.

- (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];
}

答案 7 :(得分:3)

通过调用[view addSubview:subview]“直接”添加视图。 通过交换子视图的标签栏或导航栏等方法“间接”添加视图。

每次拨打[view addSubview:subviewController.view]时,都应拨打[subviewController viewWillAppear:NO](或视情况而定)。

当我为游戏中的子屏幕实现自己的自定义根视图管理系统时,我遇到了这个问题。手动将调用添加到viewWillAppear可以解决我的问题。

答案 8 :(得分:3)

由于没有接受答案而且人们(就像我一样)落在这里,我给出了我的变化。虽然我不确定这是原来的问题。当导航控制器作为子视图添加到另一个视图时,您必须自己调用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文件中,我有视图,在这个视图下方,我有一个标签图像和容器(另一个视图),我将控制器放入其中。这是它的外观。我不得不争抢一些东西,因为这对客户来说很有用。

alt text

答案 9 :(得分:2)

一个非常常见的错误如下。 您有一个视图UIView* a,另一个视图UIView* b。 您将b添加到a作为子视图。 如果你试图在b中调用viewWillAppear,它将永远不会被触发,因为它是

的子视图

答案 10 :(得分:2)

我将此代码用于推送和弹出视图控制器:

推送:

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

流行:

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

..它对我来说很好。

答案 11 :(得分:1)

我认为添加子视图并不一定意味着视图会出现,因此没有自动调用类的方法

答案 12 :(得分:1)

对于Swift。首先创建协议以调用要在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实例分配给Navigation Controller委托属性。

答案 13 :(得分:1)

我自己就遇到了这个问题,我花了3个小时(其中2个谷歌搜索)来解决它。

原来提供帮助的只是从设备/模拟器中删除应用,清理然后再次运行

希望有所帮助

答案 14 :(得分:1)

iOS 13在这里对接我的应用程序。如果您注意到iOS 13上的行为有所变化,则在进行推送之前先进行以下设置:

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

您可能还需要在.storyboard中的“属性”检查器中进行设置(将“演示”设置为“全屏”)。

这将使您的应用像以前的iOS版本一样运行。

答案 15 :(得分:1)

[self.navigationController setDelegate:self];

将委托设置为根视图控制器。

答案 16 :(得分:1)

如果这有助于任何人。我的ViewWillAppear没有在UITableViewController上触发,我遇到了类似的问题。经过大量的游戏,我意识到问题是控制我的UINavigationController的{​​{1}}不在根视图上。一旦我解决了这个问题,它现在就像一个冠军。

答案 17 :(得分:1)

我认为它们的意思是“直接”是通过与xcode“导航应用程序”模板相同的方式挂钩,它将UINavigationController设置为应用程序UIWindow的唯一子视图。

使用该模板是我能够在UINavigationController中按下/弹出这些控制器时,在对象ViewControllers上调用Will / Did / Appear / Disappear方法的唯一方法。这里的答案中没有其他解决方案适用于我,包括在RootController中实现它们并将它们传递给(子)NavigationController。这些函数(将/将/出现/消失)仅在我的RootController中显示/隐藏顶级VC,我的“登录”和navigationVCs,而不是导航控制器中的子VC,因此我没有机会“将它们传递给Nav VC。

我最终使用UINavigationController的委托功能来查找我的应用程序中需要后续功能的特定转换,这是有效的,但它需要更多的工作才能同时获得消失和出现的功能“模拟”

在今天针对这个问题敲打几个小时后,让它开始工作也是一个原则问题。使用自定义RootController和子导航VC的任何工作代码片段都将非常受欢迎。

答案 18 :(得分:1)

我对此并不是100%肯定,但我认为直接在视图层次结构中添加视图意味着在视图控制器的视图上调用-addSubview:(例如,[viewController.view addSubview:anotherViewController.view])而不是推送新的视图控制器到导航控制器的堆栈上。

答案 19 :(得分:0)

我的问题是从segue放松时未调用viewWillAppear。答案是在您选择返回的View Controller的展开窗口中调用viewWillAppear(true)

@IBAction func unwind(用于unwindSegue:UIStoryboardSegue,ViewController随后的VC:任何){

   viewWillAppear(true)
}

答案 20 :(得分:0)

感谢iOS 13

  

ViewWillDisappearViewDidDisappearViewWillAppear和   ViewDidAppear不会在   iOS 13使用了新的模式演示,其中没有涵盖   全屏。

贷方将转到Arek Holko。他真的救了我一天。

enter image description here

答案 21 :(得分:0)

ViewWillAppear是UIViewController类的重写方法,因此添加子视图不会调用viewWillAppear,但是当您从viewController呈现push,pop,show,setFront或popToRootViewController时,将为呈现的viewController调用viewWillAppear。

答案 22 :(得分:0)

我创建了一个解决此问题的类。 只需将其设置为导航控制器的委托,并在视图控制器中实现简单的一两个方法-当视图将要显示或已通过NavigationController显示时将被调用

Here's the GIST showing the code

答案 23 :(得分:0)

就我而言,那只是ios 12.1模拟器上的一个奇怪的错误。在真实设备上启动后消失。

答案 24 :(得分:0)

就我而言,问题在于自定义过渡动画。 设置为modalPresentationStyle = .custom viewWillAppear时未调用

在自定义过渡动画类中需要调用方法: beginAppearanceTransitionendAppearanceTransition

答案 25 :(得分:-2)

我不确定这是我解决的问题。
在某些情况下,方法不能以正常方式执行,例如“[self methodOne]”。

尝试

- (void)viewWillAppear:(BOOL)animated
{
    [self performSelector:@selector(methodOne) 
           withObject:nil afterDelay:0];
}

答案 26 :(得分:-3)

您应该只有1个UIViewController在任何时候处于活动状态。您想要操纵的任何子视图都应该是 - subVIEWS - 即UIView。

我使用一种简单的技术来管理我的视图层次结构,并且因为我开始以这种方式做事,所以还没有遇到问题。有两个关键点:

  • 应使用单个UIViewController来管理“屏幕的价值” 您的应用
  • 使用UINavigationController更改视图

“屏幕值”是什么意思?它的目的有点模糊,但通常它是你的应用程序的一个功能或部分。如果你有几个屏幕具有相同的背景图像但不同的叠加/弹出窗口等,那应该是1个视图控制器和几个子视图。你永远不应该发现自己使用2个视图控制器。请注意,如果您希望屏幕的某些区域显示在多个视图控制器中,您仍然可以在一个视图控制器中实例化UIView并将其添加为另一个视图控制器的子视图。

至于UINavigationController - 这是你最好的朋友!关闭导航栏并为动画指定NO,您可以根据需要切换屏幕。如果它们位于层次结构中,您可以推送和弹出视图控制器,或者您可以准备一组视图控制器(包括包含单个VC的数组),并使用setViewControllers将其设置为视图堆栈。这使您可以完全自由地改变VC,同时获得在Apple预期模型中工作的所有优势,并使所有事件等都能正常启动。

以下是我每次启动应用时的所作所为:

  • 从基于窗口的应用开始
  • 添加UINavigationController作为窗口的rootViewController
  • 添加我想要的第一个UIViewController作为nav的rootViewController 控制器

(注意从基于窗口开始只是个人偏好 - 我喜欢自己构建内容,所以我确切地知道它们是如何构建的。它应该可以与基于视图的模板一起工作)

所有事件都正常发射,基本上生活是美好的。然后,您可以花费所有时间编写应用程序的重要部分,而不是试图手动破解视图层次结构。