I have two Present view controllers. The thing i want to do is when the second Present view controller is dismissed it will automatically reload the first present view controller(Table view). note: first view controller holds a table view, basically i want to reload the table view of first controller.
ViewWillAppear code:
override func viewWillAppear(_ animated: Bool) {
tableViewReloadFromCreateProductVC()
}
func tableViewReloadFromCreateProductVC () {
tableView.reloadData()
}
Calling from second view controller code:
SecondViewController.tableViewReloadFromCreateProductVC()
navigationController?.popViewController(animated: true)
dismiss(animated: true, completion: nil)
FirstViewController calling 2nd view controller
#IBAction func CallSecondViewButton(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController
controller.modalPresentationStyle = .fullScreen
self.present(controller, animated: true, completion: nil)
}
just write the code in viewWillAppear() method of the view controller that you want to reload like this
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
//perform api call if any
yourTableView.reloadData()
}
2nd view controller
#IBAction func CloseButton(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
after dissmissing the viewWillAppear method of firstViewController will autometically called.
The First two snippets are for first view controller and the last one is for second view controller
Reloading the entire table view could sometimes be costly and it also sounds like you're making an API call as well so unless you want your table view to be reloaded and the API call made every time the view controller becomes visible whether or not you've made changes to it, you want the reloading to be done only when it's necessary.
You can try it in a few different ways:
class CreateProductVC: UITableViewController {
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.delegate = self
present(secondVC, animated: true, completion: nil)
}
}
}
class SecondViewController: UIViewController {
weak var delegate: CreateProductVC?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
self.delegate?.tableView.reloadData()
}
}
}
or
class CreateProductVC: UITableViewController {
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.isDismissed = { [weak self] in
self?.tableView.reloadData()
}
present(secondVC, animated: true, completion: nil)
}
}
}
class SecondViewController: UIViewController {
var isDismissed: (() -> Void)?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
self.isDismissed?()
}
}
}
or if you want more fine-grained control over what to do with the new data:
protocol ReloadVC {
func reload(_ value: String)
}
class CreateProductVC: UITableViewController, ReloadVC {
var dataSource: [String]! {
didSet {
tableView.reloadData()
}
}
#IBAction func presentSecondVC() {
if let secondVC = storyboard?.instantiateViewController(identifier: "SecondVC") as? SecondViewController {
secondVC.delegate = self
present(secondVC, animated: true, completion: nil)
}
}
func reload(_ value: String) {
dataSource.append(value)
}
}
class SecondViewController: UIViewController {
var delegate: ReloadVC?
#IBAction func dismissSecondVC() {
self.dismiss(animated: true) {
let someValue = "Some Value"
self.delegate?.reload(someValue)
}
}
}
Related
I'm using NavigationController to operate the view.
If the value is exceeded on the first view and the value is not satisfied with the 'if' on the second view, I hope 'dismiss' will work.
I have made a similar simple example.
//First View
class ViewController: UIViewController {
#IBAction func goSecond(_ sender: Any) {
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DvC = Storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.navigationController?.pushViewController(DvC, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
//Second View
class SecondViewController: UIViewController {
#IBAction func goThird(_ sender: Any) {
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DvC = Storyboard.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController
let num = 1
DvC.num = num
self.navigationController?.pushViewController(DvC, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
//Third View
class ThirdViewController: UIViewController {
var num = Int()
override func viewDidLoad() {
super.viewDidLoad()
print("num: ")
print(num)
if(num != 2) {
print("Success")
// dismiss(animated: true, completion: nil)
// navigationController?.dismiss(animated: true, completion: nil)
} else {
print("Failed")
}
}
}
The third view shows "Success", but the codes below it do not work.
dismiss(animated: true, completion: nil) // not work
navigationController?.dismiss(animated: true, completion: nil) // not work
Pressing the button on the first view moves to the second view, and pressing the button on the second view moves to the third view.
If the value passed when I go to the third view is not satisfied with 'if', I want to go back to the first view.
I want the second and third views to end, not just the screen shift.
Like the finish() of Android.
How can I exit the second and third views and return to the first view?
You are pushing the view controllers onto the stack. dismiss is for dismissing VCs presented modally.
What you want to do is pop the VC to go back one.
navigationController?.popViewController(animated: true)
or to go back to the root view.
navigationController?.popToRootViewController(animated: true)
I am new to iOS swift. I have three ViewController.
The page-A is root controller and it will present to the page-B. It has a timer in page-B. After 5 sec, it will change View from page-B to page-C , and close the page-B at the same time.
In the ViewControll-B
class AViewController: UIViewController {
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
//set the timer , and chagne view to C ViewController
Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(self.changeToAnswerView),
userInfo: nil,
repeats: false)
}
#objc func changeToAnswerView() {
dismissLoader()
}
func dismissLoader() {
dismiss(animated: true) {
print("Dismissing Loader view Controller")
}
}
override func viewWillDisappear(_ animated: Bool) {
//change view to Answer ViewController
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
self.present(filterVC, animated: true, completion: nil)
}
}
After timer execute for 5 sec , the BViewController will dismiss itself and present to the BViewController.
But the following error will happened:
whose view is not in the window hierarchy
Did I missing something?
Question:
How to dismiss the current ViewController and change to the new ViewController in Swift?
Thanks in advance.
Here is the Working code that you can Try
Your Controller which is Dismissed and Tend to make a new controller being presented
import UIKit
class pdfVC: UIViewController
{
var timer : Timer?
override func viewDidLoad()
{
super.viewDidLoad()
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(pdfVC.timerAction), userInfo: nil, repeats: false)
}
#objc func timerAction()
{
if timer != nil {
timer?.invalidate()
dismiss(animated: true, completion: {
print("Dismissed")
})
}
}
override func viewWillDisappear(_ animated: Bool) {
if self.isBeingDismissed {
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "demoViewController")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
print("called")
self.presentingViewController?.present(filterVC, animated: true, completion: nil)
}
}
}
Output
Try changing dismissLoader function to something like:
func dismissLoader() {
dismiss(animated: true) {
print("Dismissing Loader view Controller")
if let presentingController = self.presentingViewController {
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "BViewControllerID")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
presentingController.present(filterVC, animated: true, completion: nil)
}
}
}
and remove the viewWillDisappear function.
The problem is that you are trying to present the BViewController from the loader after being dismissed (i.e removed from window hierarchy) which at that point doesn't exist.
So, the solution is that you could get a reference to the presenting view controller which is presenting the loader and which will appear after dismissing the loader and present the new view controller from there.
in your B view controller after its dismissed,
in its completion handler
self.dismiss(animated: true) {
if let presentingVC = self.presentingViewController {
present c view controller here
}
}
this above is one way to do so, another way is, through delegate
in A view controller:
if let bVC = self.storyboard.instantiateViewController(withIdentifier: B.controllerIdentifier) as? B {
bVC.delegate = self
self.present(bVC, animated: true, completion: nil)
}
inside B View Controller
add delegate method for Protocol
protocol BProtocol: class {
func didClose()
}
and in B dismiss
var delegate: BProtocol?
self.dismiss(animated: true) {
self.delegate?.didClose()
}
this delegate will be implemented by A ViewController as
extension AViewController: BProtocol {
func didClose() {
//present C
}
}
You are trying use a reference (instance) of view controller, that would no longer exist in memory.
Try this
if let presentingVC = self.presentingViewController {
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
presentingVC.present(filterVC, animated: true, completion: nil)
}
Note: Present a new view controller (filterVC) once your current view controller is dismissed. A view controller can present only a one view controller at time (if you choose present modally). Perform this operation after a delay of 1 second..
Edit
Try with this edited code.
Class AViewController: UIViewController {
var timer: Timer?
var presentingVC: UIViewController?
override func viewDidLoad() {
super.viewDidLoad()
//set the timer , and chagne view to C ViewController
Timer.scheduledTimer(timeInterval: 5,
target: self,
selector: #selector(self.changeToAnswerView),
userInfo: nil,
repeats: false)
}
#objc func changeToAnswerView() {
dismissLoader()
}
func dismissLoader() {
dismiss(animated: true) {
print("Dismissing Loader view Controller")
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//change view to Answer ViewController
if let presentingVC = self.presentingViewController {
self.presentingVC = presentingVC
}
}
override func viewWillDisappear(_ animated: Bool) {
//change view to Answer ViewController
super.viewWillDisappear(animated)
if let presentingVC = self.presentingVC {
let filterVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CViewControllerID")
filterVC.modalPresentationStyle = UIModalPresentationStyle.custom
presentingVC?.present(filterVC, animated: true, completion: nil)
} else {
print("Presenting View controller is nil")
}
}
}
I have implemented delegate in LoginViewController defined in RegistrationViewController. Callback function is calling but the problem is that I am not able to update the textfield of LoginViewController in delegate method.
LoginViewController.swift
import UIKit
class LoginViewController :UIViewController,RegisterViewDelegate {
#IBOutlet weak var mobileNumber: UITextField!
#IBAction func showRegistrationView(_ sender: Any) {
let controller = storyboard?.instantiateViewController(withIdentifier: "registration") as! RegistrationViewController
controller.delegate = self
present(controller, animated: false, completion: nil)
}
func onUserRegistrationCompletion(number: String) {
print(number) // output is 05010101010
DispatchQueue.main.async {
self.mobileNumber.text! = number
print(self.mobileNumber.text!) . // output is empty
}
}
}
RegistrationViewController.swift
import UIKit
class RegistrationViewController: UIViewController {
weak var delegate:RegisterViewDelegate?
#IBAction func register(_ sender: Any) {
self.delegate?.onUserRegistrationCompletion(number: "05010101010")
let controller = self.storyboard?.instantiateViewController(withIdentifier: "login")
present(controller!, animated: false, completion: nil)
}
}
protocol RegisterViewDelegate:class {
func onUserRegistrationCompletion(number:String)
}
it means you allocating the memory again on self.storyboard?.instantiateViewController(withIdentifier: "login") in Register VC, that the reason your delegate is by default goes to nil.
#IBAction func register(_ sender: Any) {
self.delegate?.onUserRegistrationCompletion(number: "05010101010")
self.dismiss(animated: true, completion:nil)
}
I suggest you to use navigationController.
and you can push to next view this way:
let controller = storyboard?.instantiateViewController(withIdentifier: "registration") as! RegistrationViewController
controller.delegate = self
self.navigationController?.pushViewController(controller, animated: true)
and when you want to go back to previous view use this code:
self.delegate?.onUserRegistrationCompletion(number: "05010101010")
self.navigationController?.popViewController(animated: true)
And your result will be:
Check THIS sample for more info.
And don't forget to Embed In your LoginViewController into navigationController from storyboard. as shown in demo project.
I have a PageViewController and three view controllers. I want to move to previous and next page with button click. I have three VCs and when I run, I'm in the second one, (main).
Ordered items: (in MainViewController class), and pageViewController is an instance of PageViewController class.
override func viewDidLoad() {
super.viewDidLoad()
orderedItems = self.pageViewController.orderedViewControllers
}
orderdViewControllers in PageViewController Class
private(set) lazy var orderedViewControllers: [UIViewController]? = {
return [
self.newViewController(id: "first"),
self.newViewController(id: "main"),
self.newViewController(id: "second")
]
}()
private func newViewController(id: String) -> UIViewController {
return UIStoryboard(name: "Main", bundle: nil) .
instantiateViewController(withIdentifier: "\(id)")
}
this is my code for button taps: (in MainViewController class)
#IBAction func leftBtnPressed(_ sender: AnyObject) {
self.pageViewController.setViewControllers([(orderedItems?.first)!], direction: .reverse, animated: true, completion: nil)
}
#IBAction func rightBtnPressed(_ sender: AnyObject) {
self.pageViewController.setViewControllers([(orderedItems?.last)!], direction: .forward, animated: true, completion: nil)
}
but it fails, nothing happens. How can I do it?
Hi I'm trying to present a viewcontroller and dismiss my current modal view but this code is not working
self.dismissViewControllerAnimated(true, completion: {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("OrderViewController")
self.presentViewController(vc!, animated: true, completion: nil)
})
vice versa is not working too on completion block of presentviewcontroller
EDIT: replaced vc! to self
You have to get the viewController which presented self (current ViewController). If that view controller is rootViewController, then you can use the code below, if not then query it based on your view controller hierarchy.
if let vc3 = self.storyboard?.instantiateViewController(withIdentifier: "vc3") as? ViewController3 {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController!.present(vc3, animated: true, completion: nil)
}
you can't do that because when the UIViewController A calls the UIViewController B and the first controller is dismissed then the two controllers are nil.
You need to have a UIViewController as a base, in this case MainViewController is the base. You need to use a protocol to call the navigation between controllers.
you can do using protocol let say for example as bellow:-
In to your viewController setting Protocol :
protocol FirstViewControllerProtocol {
func dismissViewController()
}
class FirstViewController: UIViewController {
var delegate:FirstViewControllerProtocol!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func goBack(sender: AnyObject) {
self.dismissViewControllerAnimated(true) {
self.delegate!.dismissViewController()
}
}
Now in your main view controller
class MainViewController: UIViewController, FirstViewControllerProtocol {
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.
}
#IBAction func goToFirstViewController(sender: AnyObject) {
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(String(FirstViewController)) as! FirstViewController
viewController.delegate = self
self.presentViewController(viewController, animated: true, completion: nil)
}
//MARK: Protocol
func dismissViewController() {
if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(String(SecondViewController)){
self.presentViewController(viewController, animated: true, completion: nil)
}
}
Code example with storyboard:
I think there is a mistake in your code where 'self' should be the presenting view controller to present 'vc', not 'vc' its self
Your code
self.dismissViewControllerAnimated(true, completion: {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("OrderViewController")
vc!.presentViewController(vc!, animated: true, completion: nil)
})
Try this
self.dismissViewControllerAnimated(true, completion: {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("OrderViewController")
self.presentViewController(vc!, animated: true, completion: nil)
})
hope this is helpful
let parent = self.parentViewController!
parent.dismissViewControllerAnimated(true, completion: {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("OrderViewController")
parent.presentViewController(vc!, animated: true, completion: nil)
})
Here's a solution for Swift3
To present the ViewController
let NotificationVC = self.storyboard?.instantiateViewController(withIdentifier: "NotificationVC") as! ExecutiveNotificationViewController
self.present(NotificationVC, animated: true, completion: nil)
To dismiss the ViewController:
self.dismiss(animated: true, completion: nil)