Here is my code
self.slideMenuController()?.changeMainViewController(contactNVC, close: true)
contactNVC = ContactUsViewController.swift
contactNVC is working normally.
Go to another viewcontroller
Does not work when returning to contactNVC.
ContactUsViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
print("ContactUsViewController is here")
}
First this "ContactUsViewController is here" will be printed.
When I call another view controller and come back to this ContactUsViewController.swift, this "ContactUsViewController is here" doesn't appear.
SlideMenuController /this is code from github/
https://github.com/dekatotoro/SlideMenuControllerSwift
self.slideMenuController()?.changeMainViewController(contactNVC, close: true)
You should use viewWillAppear() or viewDidAppear() method. These methods called every time your view controller is displayed on the screen.
Because viewDidLoad() is usually called once, when the VC is loaded. Sometimes it can be called multiple times. For example, if there is a memory warning sent, your VC will unload the view from memory, and the next time viewDidLoad() will be called again. But it will never be called consecutively. So just use viewWillAppear() or viewDidAppear() method, it will fire when view controller will be displayed, anyway.
Related
I'm trying to keep a timer running even if I switch view controllers. I played around with the Singleton architecture, but I don't quite get it. Pushing a new view controller seems a little easier, but when I call the below method, the view controller that is pushed is blank (doesn't look like the view controller that I created in Storyboards). The timer view controller that I'm trying to push is also the second view controller, if that changes anything.
#objc func timerPressed() {
let timerVC = TimerViewController()
navigationController?.pushViewController(timerVC, animated: true)
}
You need to load it from storyboard
let vc = self.storyboard!.instantiateViewController(withIdentifier: "VCName") as! TimerViewController
self.navigationController?.pushViewController(timerVC, animated: true)
Not sure if your problem is that your controller is blank or that the timer resets. Anyway, in case that you want to keep the time in the memory and not deallocate upon navigating somewhere else I recommend you this.
Create some kind of Constants class which will have a shared param inside.
It could look like this:
class AppConstants {
static let shared = AppConstants()
var timer: Timer?
}
And do whatever you were doing with the timer here accessing it via the shared param.
AppConstants.shared.timer ...
There are different parts to your question. Sh_Khan told you what was wrong with the way you were loading your view controller (simply invoking a view controller’s init method does not load it’s view hierarchy. Typically you will define your view controller’s views in a storyboard, so you need to instantiate it from that storyboard.)
That doesn’t answer the question of how to manage a timer however. A singleton is a good way to go if you want your timer to be global instead of being tied to a particular view controller.
Post the code that you used to create your singleton and we can help you with that.
Edit: Updated to give the TimeManager a delegate:
The idea is pretty simple. Something like this:
protocol TimeManagerDelegate {
func timerDidFire()
}
class TimerManager {
static let sharedTimerManager = TimerManager()
weak var delegate: TimeManagerDelegate?
//methods/vars to manage a shared timer.
func handleTimer(timer: Timer) {
//Put your housekeeping code to manage the timer here
//Now tell our delegate (if any) that the timer has updated.
//Note the "optional chaining" syntax with the `?`. That means that
//If `delegate` == nil, it doesn't do anything.
delegate?.timerDidFire() //Send a message to the delegate, if there is one.
}
}
And then in your view controller:
//Declare that the view controller conforms to the TimeManagerDelegate protocol
class SomeViewController: UIViewController, TimeManagerDelegate {
//This is the function that gets called on the current delegate
func timerDidFire() {
//Update my clock label (or whatever I need to do in response to a timer update.)
}
override func viewWillAppear() {
super.viewWillAppear()
//Since this view controller is appearing, make it the TimeManager's delegate.
sharedTimerManager.delegate = self
}
In My application contain five different tabs. When I switch between tabs initialization of boolean variable automatically called again and again.
When I put a breakpoint on declaration/initialization variable it will be automatically called. This will leads to change my boolean variable value to true. Please go through the following code
How to resolve this issue. Please help me
class HomeViewController: BaseViewController {
var isEnabled: Bool = true
}
override func viewWillAppear(_ animated: Bool) {
isEnabled = true
}
override func viewWillDisappear(_ animated: Bool) {
isEnabled = false
}
You are using tab view for your app. When you switch from one tab to other tab viewWillAppear called and your boolean variable isEnabled is set to true and when move to new tab it called viewWillDisappear and set to false. If you don't want to change in isEnabled variable then remove from viewWillAppear and viewWillDisappear then value will not be changed. You will get last value assigned to variable.
viewDidLoad method will call only once a life time of viewController and that is when viewController object will first load in memory. where as viewWillAppear method will call every time when a view will appear to screen or you can say will be topViewController...
Explanation: Tab1 associated with viewController1 and tab2 is associated with viewController2. Now when you will run your app and you will see tab one is selected and viewController1 is on view and you want to change to tab2, when you will tap on tab2 then tabVieController2's object will create and load to memory first time hence its viewDidLoad method will call, and soon after that it will appear to window and viewWillAppear will also get call. Now if you you try changing tabs by click on them only viewWillAppear methods will get called for both, as they are in memory already.
I've a table view with navigation controller embedded in. I've added a UIBarButtonItem (add) button. When I click this button it opens a new view where user enters the data and submits it (which makes a web service call) and returns back to the previous view. This navigation happens as shown below,
func addTapped(_ sender:UIBarButtonItem) {
print("Called Add")
let vc = (storyboard?.instantiateViewController( withIdentifier: "newNote")) as! newNoteVC
self.navigationController?.pushViewController(vc, animated: true)
}
And in new view I do following,
#IBAction func saveButton(_ sender: UIButton) {
if (self.noteDescription.text?.isEmpty)! {
print("Enter missing note description")
return
} else {
let desc = self.noteDescription.text
self.uploadNote(noteText: desc!, noteDate: self.dateInMilliseconds)
self.navigationController?.popViewController(animated: true)
}
}
This way a record gets saved and a view gets popped from the navigation controller stack but only thing I don't how to do is refresh the table view data in the parent view (where I might need to make a new http service call to read all the records).
I hope I'm able to explain the issue? Any help is appreciated.
As mentioned in the comments, making a service call just to update the tableview might be a overkill. However, if this is the business scenario which needs to be implemented, you can do the same in
func viewWillAppear
in the parent view controller. You can make the service call in this method and reload the table view with the data.
You would also need to check the overall navigation of the application as making service calls in viewWillAppear method is not a good approach as these gets called everytime the view is shown. For Ex: If coming back from a navigated view then also the method is called.
I just recently started to use Swift and am facing a "weird" bug with the viewDidLoad method.
My very simple app currently only has 2 viewcontrollers:
MainViewController, which is the Apps entry point and serves as an overview for the data which has already been created. It also provides the option to add new data, which would trigger a segue to
DataViewController, which provides the UI to create new data, after which it goes back to the MainViewController
Now my issue is that the viewDidLoad method of MainViewController is always called whenever the MainViewController appears (At the start of the app and every time the DataViewController disappears). Particularly, the msg "MainViewController newly created" is always printed.
Even worse, it seems that my app is "secretly" resetting. To show this I have defined the class variable "createView" in my MainViewController which is true by default, and is set to false during the viewDidLoad (the only place where this variable is called/set). However the msg "MVC newly created" is still always printed in the output after the MainViewController shows up. How can that be? Why / how is createView reset to true?
Hope this snippet is enough to find the issue. Otherwise, let me know if something is missing.
Thanks for your help!
override func viewDidLoad()
{
super.viewDidLoad()
if (createView)
{
determineArraySize()
createDataArray()
print("MainViewController newly created")
createView = false
}
else {print("Nothing happened")}
}
As #moritz mentioned in the comments, check out the way you present the DataViewController in your storyboard.
If the view is presented modally, you should call:
dismiss(animated: true, completion: nil)
If the view is presented using a show seque, you should call:
_ = navigationController?.popViewControllerAnimated(true)
A user is in a view controller which calls a modal. When self.dismissViewController is called on the modal, a function needs to be run on the initial view controller. This function also requires a variable passed from the modal.
This modal can be displayed from a number of view controllers, so the function cannot be directly called in a viewDidDisappear on the modal view.
How can this be accomplished in swift?
How about delegate?
Or you can make a ViewController like this:
typealias Action = (x: AnyObject) -> () // replace AnyObject to what you need
class ViewController: UIViewController {
func modalAction() -> Action {
return { [unowned self] x in
// the x is what you want to passed by the modal viewcontroller
// now you got it
}
}
}
And in modal:
class ModalViewController: UIViewController {
var callbackAction: Action?
override func viewDidDisappear(_ animated: Bool) {
let x = … // the x is what you pass to ViewController
callbackAction?(x)
}
}
Of course, when you show ModalViewController need to set callbackAction like this modal.callbackAction = modalAction() in ViewController
The answer supplied and chosen by the question asker (Michael Voccola) didn't work for me, so I wanted to supply another answer option. His answer didn't work for me because viewDidAppear does not appear to run when I dismiss the modal view.
I have a table and a modal VC that appears and takes some table input. I had no trouble sending the initial VC the modal's new variable info. However, I was having trouble getting the table to automatically run a tableView.reloadData function upon dismissing the modal view.
The answer that worked for me was in the comments above:
You likely want to do this using an unwind segue on the modal, that
way you can set up a function on the parent that gets called when it
unwinds. stackoverflow.com/questions/12561735/… – porglezomp Dec 15
'14 at 3:41
And if you're only unwinding one step (VC2 to VC1), you only need a snippet of the given answer:
Step 1: Insert method in VC1 code
When you perform an unwind segue, you need to specify an action, which
is an action method of the view controller you want to unwind to:
#IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
//Insert function to be run upon dismiss of VC2
}
Step 2: In storyboard, in the presented VC2, drag from the button to the exit icon and select "unwindToThisViewController"
After the action method has been added, you can define the unwind
segue in the storyboard by control-dragging to the Exit icon.
And that's it. Those two steps worked for me. Now when my modal view is dismissed, my table updates. Just figured I'd add this, in case anyone else's issue wasn't solved by the chosen answer.
I was able to achieve the desired result by setting a Global Variable as a boolean value from the modal view controller. The variable is initiated and made available from a struct in a separate class.
When the modal is dismissed, the viewDidAppear method on the initial view controller responds accordingly to the value of the global variable and, if needed, flips the value on the global variable.
I am not sure if this is the most efficient way from a performance perspective, but it works perfectly in my scenario.