可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I\'ve read numerous posts about people having problems with viewWillAppear
when you do not create your view hierarchy just right. My problem is I can\'t figure out what that means.
If I create a RootViewController
and call addSubView
on that controller, I would expect the added view(s) to be wired up for viewWillAppear
events.
Does anyone have an example of a complex programmatic view hierarchy that successfully receives viewWillAppear
events at every level?
Apple\'s Docs state:
Warning: If the view belonging to a view controller is added to a view hierarchy directly, the view controller will not receive this message. If you insert or add a view to the view hierarchy, and it has a view controller, you should send the associated view controller this message directly. Failing to send the view controller this message will prevent any associated animation from being displayed.
The problem is that they don\'t describe how to do this. What does \"directly\" mean? How do you \"indirectly\" add a view?
I am fairly new to Cocoa and iPhone so it would be nice if there were useful examples from Apple besides the basic Hello World crap.
回答1:
If you use a navigation controller and set its delegate, then the view{Will,Did}{Appear,Disappear} methods are not invoked.
You need to use the navigation controller delegate methods instead:
navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:
回答2:
I\'ve run into this same problem. Just send a viewWillAppear
message to your view controller before you add it as a subview. (There is one BOOL parameter which tells the view controller if it\'s being animated to appear or not.)
[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 ;)
回答3:
I finally found a solution for this THAT WORKS!
UINavigationControllerDelegate
I think the gist of it is to set your nav control\'s delegate to the viewcontroller it is in, and implement UINavigationControllerDelegate
and it\'s two methods. Brilliant! I\'m so excited i finally found a solution!
回答4:
I just had the same issue. In my application I have 2 navigation controllers and pushing the same view controller in each of them worked in one case and not in the other. I mean that when pushing the exact same view controller in the first UINavigationController
, viewWillAppear
was called but not when pushed in the second navigation controller.
Then I came across this post UINavigationController should call viewWillAppear/viewWillDisappear methods
And realized that my second navigation controller did redefine viewWillAppear
. Screening the code showed that I was not calling
[super viewWillAppear:animated];
I added it and it worked !
The documentation says:
If you override this method, you must call super at some point in your implementation.
回答5:
I\'ve been using a navigation controller. When I want to either descend to another level of data or show my custom view I use the following:
[self.navigationController pushViewController:<view> animated:<BOOL>];
When I do this, I do get the viewWillAppear
function to fire. I suppose this qualifies as \"indirect\" because I\'m not calling the actual addSubView
method myself. I don\'t know if this is 100% applicable to your application since I can\'t tell if you\'re using a navigation controller, but maybe it will provide a clue.
回答6:
Firstly, the tab bar should be at the root level, ie, added to the window, as stated in the Apple documentation. This is key for correct behavior.
Secondly, you can use UITabBarDelegate
/ UINavigationBarDelegate
to forward the notifications on manually, but I found that to get the whole hierarchy of view calls to work correctly, all I had to do was manually call
[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];
and
[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];
.. just ONCE before setting up the view controllers on the respective controller (right after allocation). From then on, it correctly called these methods on its child view controllers.
My hierarchy is like this:
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
Just calling the mentioned methods on the tab/nav controller the first time ensured that ALL the events were forwarded correctly. It stopped me needing to call them manually from the UINavigationBarDelegate
/ UITabBarControllerDelegate
methods.
Sidenote:
Curiously, when it didn\'t work, the private method
- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController
.. which you can see from the callstack on a working implementation, usually calls the viewWill/Did..
methods but didn\'t until I performed the above (even though it was called).
I think it is VERY important that the UITabBarController
is at window level though and the documents seem to back this up.
Hope that was clear(ish), happy to answer further questions.
回答7:
As no answer is accepted and people (like I did) land here I give my variation. Though I am not sure that was the original problem. When the navigation controller is added as a subview to a another view you must call the viewWillAppear/Dissappear etc. methods yourself like this:
- (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];
}
the .h looks like this
@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
IBOutlet UIView *subNavContainer;
UINavigationController *subNavCntlr;
}
@end
In the nib file I have the view and below this view I have a label a image and the container (another view) where i put the controller in. Here is how it looks. I had to scramble some things as this was work for a client.
回答8:
Views are added \"directly\" by calling [view addSubview:subview]
.
Views are added \"indirectly\" by methods such as tab bars or nav bars that swap subviews.
Any time you call [view addSubview:subviewController.view]
, you should then call [subviewController viewWillAppear:NO]
(or YES as your case may be).
I had this problem when I implemented my own custom root-view management system for a subscreen in a game. Manually adding the call to viewWillAppear cured my problem.
回答9:
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];
}
回答10:
I use this code for push and pop view controllers:
push:
[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];
pop:
[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];
.. and it works fine for me.
回答11:
A very common mistake is as follows.
You have one view, UIView* a
, and another one, UIView* b
.
You add b to a as a subview.
If you try to call viewWillAppear in b, it will never be fired, because it is a subview of a
回答12:
I\'m not 100% sure on this, but I think that adding a view to the view hierarchy directly means calling -addSubview:
on the view controller\'s view (e.g., [viewController.view addSubview:anotherViewController.view]
) instead of pushing a new view controller onto the navigation controller\'s stack.
回答13:
I think that adding a subview doesn\'t necessarily mean that the view will appear, so there is not an automatic call to the class\'s method that it will
回答14:
I think what they mean \"directly\" is by hooking things up just the same way as the xcode \"Navigation Application\" template does, which sets the UINavigationController as the sole subview of the application\'s 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.
I ended up using the UINavigationController\'s delegate functionality to look for the particular transitions that required follow-up functionality in my app, and that works, but it requires a bit more work in order to get both the disappear and appear functionality \"simulated\".
Also it\'s a matter of principle to get it to work after banging my head against this problem for hours today. Any working code snippets using a custom RootController and a child navigation VC would be much appreciated.
回答15:
In case this helps anyone. I had a similar problem where my ViewWillAppear
is not firing on a UITableViewController
. After a lot of playing around, I realized that the problem was that the UINavigationController
that is controlling my UITableView
is not on the root view. Once I fix that, it is now working like a champ.
回答16:
I just had this problem myself and it took me 3 full hours (2 of which googling) to fix it.
What turned out to help was to simply delete the app from the device/simulator, clean and then run again.
Hope that helps
回答17:
[self.navigationController setDelegate:self];
Set the delegate to the root view controller.
回答18:
In my case problem was with custom transition animation.
When set modalPresentationStyle = .custom
viewWillAppear
not called
in custom transition animation class need call methods:
beginAppearanceTransition
and endAppearanceTransition
回答19:
For Swift. First create the protocol to call what you wanted to call in viewWillAppear
protocol MyViewWillAppearProtocol{func myViewWillAppear()}
Second, create the class
class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
updatedCntllr.myViewWillAppear()
}
}
}
Third, make the instance of ForceUpdateOnViewAppear to be the member of the appropriate class that have the access to the Navigation Controller and exists as long as Navigation controller exists. It may be for example the root view controller of the navigation controller or the class that creates or present it. Then assign the instance of ForceUpdateOnViewAppear to the Navigation Controller delegate property as early as possible.
回答20:
I\'m not sure this is the same problem that I solved.
In some occasions, method doesn\'t executed with normal way such as \"[self methodOne]\".
Try
- (void)viewWillAppear:(BOOL)animated
{
[self performSelector:@selector(methodOne)
withObject:nil afterDelay:0];
}
回答21:
You should only have 1 UIViewController active at any time. Any subviews you want to manipulate should be exactly that - subVIEWS - i.e. UIView.
I use a simlple technique for managing my view hierarchy and have yet to run into a problem since I started doing things this way. There are 2 key points:
- a single UIViewController should be used to manage \"a screen\'s worth\"
of your app
- use UINavigationController for changing views
What do I mean by \"a screen\'s worth\"? It\'s a bit vague on purpose, but generally it\'s a feature or section of your app. If you\'ve got a few screens with the same background image but different overlays/popups etc., that should be 1 view controller and several child views. You should never find yourself working with 2 view controllers. Note you can still instantiate a UIView in one view controller and add it as a subview of another view controller if you want certain areas of the screen to be shown in multiple view controllers.
As for UINavigationController - this is your best friend! Turn off the navigation bar and specify NO for animated, and you have an excellent way of switching screens on demand. You can push and pop view controllers if they\'re in a hierarchy, or you can prepare an array of view controllers (including an array containing a single VC) and set it to be the view stack using setViewControllers. This gives you total freedom to change VC\'s, while gaining all the advantages of working within Apple\'s expected model and getting all events etc. fired properly.
Here\'s what I do every time when I start an app:
- start from a window-based app
- add a UINavigationController as the window\'s rootViewController
- add whatever I want my first UIViewController to be as the rootViewController of the nav
controller
(note starting from window-based is just a personal preference - I like to construct things myself so I know exactly how they are built. It should work fine with view-based template)
All events fire correctly and basically life is good. You can then spend all your time writing the important bits of your app and not messing about trying to manually hack view hierarchies into shape.