看起来没有点火

我读过很多关于人们在使用 viewWillAppear时遇到问题的帖子,当你没有正确地创建视图层次结构 只是时。我的问题是我不知道那是什么意思。

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

是否有人有一个复杂的编程视图层次结构的例子,成功地接收 viewWillAppear事件在每个级别?

苹果文档状态:

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

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

我对 Cocoa 和 iPhone 相当陌生,所以如果除了基本的 Hello World 之外还有苹果的有用例子就好了。

104806 次浏览

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

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

当我这样做的时候,我确实得到了 viewWillAppear函数的触发。我认为这是“间接的”,因为我自己并没有调用实际的 addSubView方法。我不知道这是否100% 适用于您的应用程序,因为我不能告诉如果您正在使用导航控制器,但也许它将提供一个线索。

我也遇到过同样的问题。在将其作为子视图添加之前,只需将 viewWillAppear消息发送到视图控制器。(有一个 BOOL 参数可以告诉视图控制器它是否被动画化显示。)

[myViewController viewWillAppear:NO];

Look at RootViewController.m in the Metronome example.

(I actually found Apple's example projects great. There's a LOT more than HelloWorld ;)

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

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

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

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

我认为添加一个子视图并不一定意味着视图会出现,所以不会自动调用类的方法

我也有同样的问题。在我的应用程序中,我有两个导航控制器,在每个控制器中推动相同的视图控制器在一种情况下工作,而不是在另一种情况下。我的意思是,当在第一个 UINavigationController中推入完全相同的视图控制器时,viewWillAppear被调用,而在第二个导航控制器中被推入时则不被调用。

然后我发现了这篇文章 UINavigationController 应该调用 viewWillAppear/viewWillDisaper 方法

并且意识到我的第二个导航控制器确实重新定义了 viewWillAppear

[super viewWillAppear:animated];

我加进去了,而且成功了!

文件上说:

如果重写此方法,则必须在实现中的某个位置调用 super。

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

Using that template is the only way I've been able to get the Will/Did/Appear/Disappear methods called on the object ViewControllers upon push/pops of those controllers in the UINavigationController. None of the other solutions in the answers here worked for me, including implementing them in the RootController and passing them through to the (child) NavigationController. Those functions (will/did/appear/disappear) were only called in my RootController upon showing/hiding the top-level VCs, my "login" and navigationVCs, not the sub-VCs in the navigation controller, so I had no opportunity to "pass them through" to the Nav VC.

我最终使用 UINavigationController 的委托功能来寻找我的应用程序中需要后续功能的特定过渡,这很有效,但是需要更多的工作才能让这些功能消失并且看起来像是“模拟”的。

而且,在今天用头撞了几个小时这个问题之后,让它工作也是一个原则问题。任何使用自定义 RootController 和子导航 VC 的工作代码片段都将非常受欢迎。

以防万一。我有一个类似的问题,我的 ViewWillAppear没有在一个 UITableViewController点火。经过一番周旋,我意识到问题在于控制我的 UITableViewUINavigationController不在根视图上。一旦我解决了这个问题,它就会像冠军一样运转。

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

任何时候您调用 [view addSubview:subviewController.view],然后您应该调用 [subviewController viewWillAppear:NO](或是,视情况而定)。

当我在游戏中为子屏幕实现我自己的定制 root-view 管理系统时,我遇到了这个问题。手动添加对 viewWillAppear 的调用解决了我的问题。

[self.navigationController setDelegate:self];

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

由于没有答案被接受,人们(像我一样)登陆这里,我给我的变化。虽然我不确定这是最初的问题。当导航控制器作为子视图被添加到另一个视图时,你必须像下面这样调用 viewWillAppear/Dislose 等方法:

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


[subNavCntlr viewWillAppear:animated];
}


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


[subNavCntlr viewWillDisappear:animated];
}

Just to make the example complete. This code appears in my ViewController where I created and added the the navigation controller into a view that I placed on the view.

- (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

我终于找到了解决这个问题的办法!

UINavigationController

我认为它的要点是将导航控制的委托设置为视图控制器中的视图控制器,并实现 UINavigationControllerDelegate和它的两个方法。太棒了!我太激动了,我终于找到解决办法了!

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

其次,可以使用 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方法手动调用它们。

旁注: Curiously, when it didn't work, the private method

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

..您可以从工作实现的调用堆栈中看到,它通常调用 viewWill/Did..方法,但是直到我执行上述操作之后才调用(即使它被调用)。

我认为这是非常重要的 UITabBarController是在窗口级虽然和文件似乎支持这一点。

希望这是明确的(或许) ,乐意回答进一步的问题。

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

我使用一种简单的技术来管理视图层次结构,自从我开始这样做以来,还没有遇到过问题。这里有两个关键点:

  • 一个单独的 UIViewController 应该被用来管理“屏幕的价值” 你的应用程序
  • use UINavigationController for changing views

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

至于 UINavigationController-这是你最好的朋友!关闭导航栏并为动画指定“ NO”,这样你就可以根据需要切换屏幕了。如果视图控制器处于层次结构中,您可以推送和弹出视图控制器,或者您可以准备一个视图控制器数组(包括一个包含单个 VC 的数组) ,并使用 setViewController 将其设置为视图堆栈。这给了你改变 VC 的完全自由,同时获得所有的优势,在苹果的预期模式下工作,并得到所有的事件等适当解雇。

Here's what I do every time when I start an app:

  • 从一个基于窗口的应用程序开始
  • 添加一个 UINavigationController 作为窗口的 rootViewController
  • 添加任何我希望我的第一个 UIViewController 作为导航的 rootViewController 控制器

(注意,从基于窗口开始只是个人偏好-我喜欢自己构建事物,这样我就能确切地知道它们是如何构建的。使用基于视图的模板应该可以很好地工作)

所有的事情都能正确地发生,基本上生活是美好的。然后你就可以把所有的时间都花在写应用程序的重要部分上,而不用费力地手动将视图层次结构修改成形状。

I'm not sure this is the same problem that I solved.
在某些情况下,方法不会以正常的方式执行,例如“[ self methodOne ]”。

试试看

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

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

推:

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

pop:

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

我觉得挺好的。

我自己也有这个问题,我花了整整3个小时(其中2个小时在谷歌上)来解决它。

结果证明,简单地使用 从设备/模拟器中删除应用程序,清理,然后再次运行是有帮助的。

希望能帮上忙

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

正确的方法是使用 UIViewController 包含 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];
}

在我的情况下,问题是与自定义过渡动画。 当设置为 modalPresentationStyle = .custom时,viewWillAppear不被调用

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

首先创建一个协议来调用在 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 的实例分配给导航控制器委托属性。

在我的例子中,这只是 ios 12.1模拟器上的一个奇怪的 bug,在真正的设备上启动之后就消失了。

I have created a class that solves this problem. 只需将它设置为导航控制器的一个委托,并在视图控制器中实现一个或两个简单的方法——当视图即将显示或通过 NavigationController 显示时,将调用这些方法

Here's the GIST showing the code

ViewWillAppear is an override method of UIViewController class so adding a subView will not call viewWillAppear, but when you present, push , pop, show , setFront Or popToRootViewController from a viewController then viewWillAppear for presented viewController will get called.

谢谢 iOS 13。

ViewWillDisappearViewDidDisappearViewWillAppearViewDidAppear won't get called on a presenting view controller on IOS13使用了一个新的模态表示,它不包括 整个屏幕。

学分归 Arek Holko了,他真的救了我一命。

enter image description here

IOS13让我的应用吃了大亏。如果你已经注意到 iOS13的行为变化,在你按下它之前设置如下:

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

您可能还需要在属性检查器(将演示设置为全屏)中的. Storyboard 中设置它。

这将使您的应用程序的行为,因为它在以前的版本的 iOS。

我的问题是,viewWillAppear 在结束转换时没有被调用。答案是在视图控制器中调用 viewWillAppear (true) ,然后返回视图控制器

@ IBAction func unwind (用于 unwindSegue: UIStoryboardSegue,ViewController 嗣后 VC: Any){

   viewWillAppear(true)
}