For some reason, my viewWill/DidAppear methods aren't being called. Here is the way I'm presenting my view controller:
let profileViewVM = ProfileViewViewModel()
let profileViewController = ProfileViewController(viewModel: profileViewVM)
self.navigationController?.pushViewController(profileViewController, animated: true)
override func viewDidLoad() {
super.viewDidLoad() // <---- breakpoint set here gets hit
// do stuff
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) // <---- breakpoint set here does NOT get hit
// do stuff
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) // <---- breakpoint set here does NOT get hit
// do stuff
}
Every other question I've seen with this issue has been something to do with not setting up a child controller correctly, not calling the super methods, or calling the wrong super message. This isn't a child controller - it's being presented by a navigationController, and as you can see I'm calling the correct super methods. I'd appreciate any input on why these aren't being hit, I'm stumped
Related
My iOS App starts with UIViewController A which is embedded as first element in a UINavigationController. When the app is started or when returning to it after some time in background I would like to show a password prompt. In this case UIViewController A should present UIViewController B which shows the password prompt.
The user should immediately see UIViewController B, not A and then B sliding in, etc. Thus, I have presented UIViewController B in viewWillAppear in UIViewController A:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if needPassword {
let passwordVC = PasswordViewController()
passwordVC.modalPresentationStyle = .fullScreen
present(passwordVC, animated: false, completion: nil)
}
}
This works fine, but an error message is logged:
Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0x7fe9af01c200>.
It is obvious that presenting UIViewController B from UIViewController A before it became visible causes this problem. Moving from viewWillAppear to viewDidAppear would solve the error message. However, than the user would first see A then B...
Is it even possible to overlay a ViewControler A with ViewController B without A becoming visible first?
I know that there might be other solutions like adding the view of the password ViewController manually to the view hierachy, etc. However, I would prefer a clean way where A is in complete control. Is this possible?
Or is it save to simple ignore the warning?
It sounds a bit tricky, might do the job though.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if needPassword {
self.view.alpha = 0
// Maybe (or not?)
self.navigationController?.view.backgroundColor = .white
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if needPassword {
let passwordVC = PasswordViewController()
passwordVC.modalPresentationStyle = .fullScreen
present(passwordVC, animated: false, completion: { [weak self] in
self?.view.alpha = 1
})
}
}
1)videovc.swift
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.createTimerView()
}
2)MyvideosVC.swift
#objc func btnBackTapping(_ sender: UIButton) {
self.navigationController?.popViewController(animated: true)
}
on backtapping i want to hide createTimerView() function when viewDidAppear method call again, if Anyone can help that would be greatful Thakyou in Advance.
Move it in viewDidLoad and it will be called only on once per creation
override func viewDidLoad() {
super.viewDidLoad()
self.createTimerView()
}
So, There is concept called ViewController Lifecycle.
ViewDidLoad is method which gets called only once in the life cycle of ViewControlller
I would highly recommend you to go through this article:
https://medium.com/good-morning-swift/ios-view-controller-life-cycle-2a0f02e74ff5
I'm developing a shopping list like app where I have a Navigation Controller and the root view controller is the screen where the user can search for products (SearchViewController). When the user selects a product it segues to DetailViewController. This view has an option to check out or add more products. If users click on "Add more products" I have to segue to SearchViewController so they can search for more products. I want to present this VC again but I want the Nav Bar to show this time since I want to be able to go back if I decide not to add any other products.
Right now I'm sending the shoppingContext in the segue to determine from the SearchVC if I come from "DetailsVC" or not.
I think there's a problem with the way I'm adding view controllers to the navigation stack, but I've never encountered a problem like this and don't know what else to try.
With my current implementation (performSegue from DetailsVC to SearchVC) any time I click on a new item it segues twice to the Details screen, which I suspect may also be caused by the same navigation stack issue.
I tried creating a new object of SearchVC and pushing it to the stack instead of performing the segue but it didn't work either.
What can I do to fix it?
Basically, in detailsVC I do the following:
let segueAction = SegueAction(name: "segueToSearch", preparer: {
destinationVC in
if
let activeVC = destinationVC as? SearchViewController
{
activeVC.shoppingList = self.shoppingViewModel.shoppingList
}
})
performSegue(withIdentifier: segueAction.name, sender: segueAction)
The segue "segueToSearch" is a Show (push) type segue.
Then in the SearchVC I check if shoppingList != nil and if so do:
navigationController?.setNavigationBarHidden(false, animated: false)
If I check if the navigation bar is hidden it returns false but I still don't see it.
Hi it's pretty straight forward. Answer can be found here:
Navigation bar show/hide
[[self navigationController] setNavigationBarHidden:NO animated:YES];
And I would put a property to check in the viewWillApear.
-- EDIT: --
TESTED: I added it to a button action, works also in the viewDidAppear when dismiss back from to detail.
Hope it helps.
class ViewController: UIViewController {
var didHideNav: Bool = false
#IBAction func changeHidden(_ sender: UIButton) {
if !didHideNav {
print("Should Be Hidden")
self.navigationController?.setNavigationBarHidden(true, animated: true)
didHideNav = true
}else{
print("Should Be Visible")
self.navigationController?.setNavigationBarHidden(false, animated: true)
didHideNav = false
}
}
override func viewDidAppear(_ animated: Bool) {
if !didHideNav {
print("Should Be Hidden")
self.navigationController?.setNavigationBarHidden(true, animated: true)
didHideNav = true
}else{
print("Should Be Visible")
self.navigationController?.setNavigationBarHidden(false, animated: true)
didHideNav = false
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I have UIViewController and I created my custom class for its view. By the way, I redefined method "canBecomeFirstResponder" in that class so it always returns true. I want my view to become first responder when the viewDidAppear method is called. But after I go to another controller and come back my program crashes. Can not understand why does this happens. Here is some code:
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
self.firstResponder = self.view.isFirstResponder()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if(self.firstResponder){
self.view!.becomeFirstResponder()
}
}
This link helped me a lot. https://stackoverflow.com/a/21906038/4092466 I should not have named the property "firstResponder". When I renamed it everything worked fine.
I have a split view controller. Everything loads properly, except when you're in portrait and you rotate to landscape, the cell current gets de-selected.
I found the problem. The table was reloading data every time the viewWillAppear function was called, and viewWillAppear is called every time the device is rotated.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
table.reloadData()
}
Now there's a new issue. I need to update the TableView whenever I add an item from a modal view.
The modal view is another view controller. I tried:
MasterViewContoller().table.reloadData()
That raised a bunch of flags and I'm pretty sure that's not the right way to do it. So how can I reload the table from another view?
==============
For those think that the ViewWillAppear is not called on rotation, try this and see:
class MasterViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
println("rotated")
}
}
class DetailedViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
The standard solution to your problem is to use a delegate.
protocol ModalViewControllerDelegate {
func updateInModalViewController(sender: ModalViewController)
}
class MainViewController: UIViewController, ModalViewControllerDelegate {
func prepareForSegue(_ segue: UIStoryboardSegue, sender sender: AnyObject?) {
if let controller = segue.destinationViewController as? ModalViewController {
controller.delegate = self
}
}
// the rest should be pretty obvious
}