I'm developing an app for iPhone and iPad. The app has a TabBar to switch between ViewControllers. I know that when the app is developed for both devices all I have to do is create the Storyboard items again for iPad and just connect the properties with the ViewControllers that I already have i.e FirstViewController is the same for the iPhone and iPad app.
In the iPhone app there are three tabs but because iPad's screen size is bigger I would like to have two tabs for the iPad version. So I would like to merge SecondViewController and ThirdViewController for the iPad app. So I decided to subclass UIViewControllerand called it MyViewController. Inside MyViewController goes the code of SecondViewController and ThridViewController.
In the simulator I can see the background image and the Storyboard items of the MyViewController's view. The problem is that viewDidLoad method doesn't get called on MyViewController class (I have a NSLog statement right after [super viewDidLoad]). I checked that in my storyboard in Idendity Inspector the class is MyViewController. Also tried to create a completely new ViewController with a new subclass but also for that new ViewController the method viewDidLoad method is not getting called.
Tab bar controllers do not release controller-A when you move to controller-B and vice versa.They are allocated once and hence you don't see viewDidLoad when the tabs are shuffled.
You might have to check viewWillAppear method to see it the viewControllers are called or not!
You could use these life cycle events:
Responding to View Events
– viewWillAppear:
– viewDidAppear:
– viewWillDisappear:
– viewDidDisappear:
– viewWillLayoutSubviews
– viewDidLayoutSubviews
- (void)viewDidAppear:(BOOL)animated
viewDidAppear will be called when your view visible again
Related
I've got a segue that opens a viewcontroller via a storyboard reference in the viewDidLoad of the parent controller. Everything worked in the earlier versions of iOS and Xcode, however it seems to give me a crash now with the message
[Assert] Assuming bar button item's view exists.
I'm not sure what to do - I've tracked the crash down to the line which references the segue that opens the referenced viewcontroller.
I've set the anchor as the bar button item.
[self performSegueWithIdentifier:#"menuPopSegue" sender:nil];
Make sure you have set the identifier in storyboard which you are calling here.
I moved my code into the viewDidAppear method instead of the viewDidLoad (where it originally was). It now works and presents the viewController in a popOver - I assume the problem was because in the viewDidLoad items were initialised but not actually presented yet on screen and the new UIPopoverPresentationController class requires the anchor and its properties to be fully loaded.
This question already has answers here:
iOS 7 - Difference between viewDidLoad and viewDidAppear
(7 answers)
Closed 6 years ago.
I am making iPhone app on swift,here ViewDidAppear and ViewWillAppear is being called multiple times on one viewDidLoad in ios swift app?
please help me.
Whenever You push a viewController, It will call viewDidLoad then viewWillAppear and last viewDidAppear.
But if you are coming back to viewController only viewWillAppear and viewDidAppear will call.
View will call these two (viewWillAppear & viewDidAppear) every time, whenever this viewController shows on every condition
i. On push - viewDidLoad after it, viewWillAppear & viewDidAppear.
ii. On back or pop - No viewDidLoad will call, Only viewWillAppear & viewDidAppear.
iii. On become active state - No viewDidLoad will call, Only viewWillAppear & viewDidAppear.
If you are not familiar with the UIViewController life cycle I really recommend you to start here Apple documentation and here.
But in a very short answer
The method viewDidLoad - This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView method. You usually override this method to perform additional initialization on views that were loaded from nib files.
The methods ViewDidAppear and ViewWillAppear as they sound to you, called every time the view Appear on the screen.
This image (from Apple documentation) shows the valid state transitions between various view ‘will’ and ‘did’ callback methods
We have a MainViewController with a tableView, and it presents a new modalViewController.
The MainViewController is restricted to portrait only, and the modalViewController can rotate.
The problem is in iOS8, that when the modalViewController rotates, the callback method of rotation in iOS8 in MainViewcontroller is called - - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
Thus, the UITableView is getting its data reloaded, which is a behaviour we don't want.
Can we prevent this feature of iOS 8, and not rotate the presenting UIViewController?
So after long days of searching and investigating, I finally came up with a possible solution.
First of all, I can use navigation controller and push the viewController instead of presenting it, but it breaks my code and just isn't so true.
The second thing I can do is not setting constraints. I still can use autolayout, but if I don't set constraints, and let the default constraints to be set, the tableView doesn't get reloaded. of course this is also isn't very smart thing to do, as I have many elements in my viewController.
Finally, I figured out that I can show this "modal" viewController in another UIWindow. I create UIWindow and set the modalViewController as its rootViewController.
I put some example project in git:
https://github.com/OrenRosen/ModalInWindow
Hope it will be helpful.
I did something similar with a navigation controller, that wouldn't rotate unless the top pushed controller does rotate.
In your case check if the main controller is presenting another controller. If it isn't then just reject rotation, otherwise return whatever the presented controller returns for the rotation method.
As for your table view, it shouldn't get reloaded because of rotations.
In iOS 8 the view that rotates when you change the device orientation is the first view added to the UIWindow. So, if you save a reference to it in your presentedController, you can overwrite the shouldAutorotate and supportedInterfaceOrientations values.
i currently wonder which init-Method is called in the ViewController via TabBarController on tapping a tab.
i tested
init, initWithStyle, initWithFrame, initWithNibName:andbundle..
but non if them seem to be called.
Any idea, which one is the correct?
for logical reasons i dont want to just use viewDidAppear/Load here..
Any clue?
thanks, Daniel
it's - (id)initWithCoder:(NSCoder *)aDecoder
But this happens before the tab is tapped.
initWithCoder: is called when the viewController is added to the UITabBarController.
If you want to respond to a tap on the tab you have to use viewWillAppear: viewDidAppear: or viewDidLoad
I am using a UISplitViewController inside a UITabBarController with a plain UIViewController in the master pane of the split view and a UINavigationController in the detail pane, which itself contains a vanilla UIViewController.
I am aware that Apple advise to use split views at the root level only, however I have seen other applications (eg, Amazon- 'Wish List' tab) that use split views in tabs so I'm sure it's possible.
My problem is that the delegate methods of the split view, ie. those in UISplitViewControllerDelegate do not get called, which prevents me from creating my pop-over menu when switching into Portrait mode.
The methods in question are the following -
// Called when a button should be added to a toolbar for a hidden view controller
- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc;
// Called when the view is shown again in the split view, invalidating the button and popover controller
- (void)splitViewController: (UISplitViewController*)svc willShowViewController:(UIViewController *)aViewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem;
// Called when the view controller is shown in a popover so the delegate can take action like hiding other popovers.
- (void)splitViewController: (UISplitViewController*)svc popoverController: (UIPopoverController*)pc willPresentViewController:(UIViewController *)aViewController;
The UISplitViewController does receive the rotation notifications.
I can get the willShowViewController method to be called if I force the status bar orientation to landscape right (or left) at the beginning of the app launch, using
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
However, the willHideViewController doesn't get called. And I don't want to force the app to start in landscape. If I do the same thing but force it to portrait, I don't receive the callbacks.
I don't understand why the split view controller is not calling it's delegate methods when it is otherwise behaving correctly. These methods should be called from its method-
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
internally, and when I breakpoint inside this, I can check that the delegate is set and that it is still alive.
Been stuck on this all day! Everything else is working great and I'm very pleased that the splitview / tabbar / navbar combination is working well. I just need these notifications.
Should I perhaps just call them manually when I rotate? Seems very wrong when the `UISplitViewController' should be doing this.
Solved, it has to be at either root level or a direct subview of a tabBar which also must be at root level. Annoying!
First, try to see if you are setting the correct delegates.
e.g., lets say you created three controllers,
UISplitViewController* splitView;
UIViewController* masterView;
UIViewController* detailView;
You implemented the delegate protocol at the detail view, so that when orientation changes, detail view should be able to put a button in the toolbar.
Now in order for splitView to call this function from delegate, you need to set the delegate itself.
So somewhere, if you are missing the following call,
splitView.delegate = detailView;
detailView's will never get notified of the orientation changes etc. At least this is where I was stuck.
I like the following method of sending a message from the master UIViewController to the detail UIViewController. Somewhere inside the master's implementation:
id detailViewController = [[self.splitViewController viewControllers] lastObject];
[detailViewController setSomeProperty:…];
This is from Paul Hegarty's Fall 2011 Stanford iTunesU iPad and iPhone Application Development course.