I am using dispatcQueue to automatically dismiss my controller but I have an issue is that it dismiss my view controller automatically but also dismiss other view controllers that are presented modally and I want to dismiss only a single view controller
func dismissViewController() {
let pickVc = UIStoryboard(name:"Main", bundle: nil).instantiateViewController(withIdentifier: "request-VC") as! RequestViewController
pickVc.modalPresentationStyle = .custom
pickVc.requestDelegate = self
present(pickVc, animated: true, completion: nil)
}
func openRequestAlertViewController() {
let pickVc = UIStoryboard(name:"Main", bundle: nil).instantiateViewController(withIdentifier: "requestAlertVC") as! RequestAlertViewController
pickVc.modalPresentationStyle = .custom
pickVc.searchDelegate = self
present(pickVc, animated: true, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 20) {
self.dismiss(animated: true, completion: nil)
}
}
func dismissRequestVC() {
let searchVc = UIStoryboard(name:"Main", bundle: nil).instantiateViewController(withIdentifier: "searching-VC") as! SearchingViewController
searchVc.modalPresentationStyle = .custom
present(searchVc, animated: true, completion: nil)
}
but it also dismiss after 20 seconds and I don't want to dismiss this. any help? This is my whole code
Create an instance for a particular viewcontroller which you want to dismiss like the following
var lvc: LoadingViewController?
func showLoadingIn(viewController: UIViewController) {
lvc = LoadingViewController() // create new instance before presentation
viewController.presentViewController(lvc!, animated: false, completion: nil)
}
func dismissLoader() {
lvc?.dismissViewControllerAnimated(true) {
print("Dismissing Loader view Controller")
}
}
You are presenting all viewControllers with the current viewController and while dismissing you are are not dismissing the currently presented viewController. Instead you are dismissing the presenter viewController so all the presented ViewControllers are also getting dismissed.
If you want to dismiss a particular viewController you can do it like this,
yourViewController.dismiss(animated: true, completion: nil)
For example in your case you can do this to dismiss the pickVc after 20 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 20) {
pickVc.dismiss(animated: true, completion: nil)
}
Related
is it possible to handle and trigger some func in first controller if second controller is dimissed?
this my code to open second controller from first controller
self.present(UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LockScreen") as UIViewController, animated: true, completion: nil)
and this my code to dismiss controller from second controller to first controller
self.navigationController?.popViewController(animated: true)
self.dismiss(animated: true, completion: nil)
Inside your LockScreen controller, declare a closure to handle when dismissed:
class LockScreen: UIViewController {
var onDismissHandler: (() -> ())?
func dismissController() {
self.dismiss(animated: true, completion: onDismissHandler)
}
}
Then when you're presenting LockScreen:
func onPresent() {
let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "LockScreen") as LockScreen
controller.onDismissHandler = { [weak self] in
// TODO: Do something when dismissed
}
self.present(controller, animated: true, completion: nil)
}
When second viewController is dismissed, trigger some func on dismissing of the current viewController.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction private func buttonClick(sender: UIButton) {
let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController")
onDismiss()
self.present(viewController, animated: false, completion: nil)
}
Trigger some func on dismissing of the current view controller
func onDismiss() {
self.dismiss(animated: false) {
print("Dismissing current view controller")
}
}
}
Here i'm dismissing one VC and trying to navigate new VC , but navigation not working. Dismiss VC working fine.
#IBAction func onClickEmailBtn(_ sender: UIButton) {
//dismiss VC
self.dismiss(animated: false, completion: nil)
//Navigate to VC
DispatchQueue.main.async {
let cevc = self.storyboard?.instantiateViewController(withIdentifier: "CEVC") as! EmailViewController
self.navigationController?.pushViewController(cevc, animated: true)
}
}
Here I have one NavigationViewController called VC1, on that I'm presenting one VC called VC2. In this VC2 when I click button I want to navigate new VC called EmailVC.
try this code
#IBAction func onClickEmailBtn(_ sender: UIButton) {
if let controller = self.storyboard?.instantiateViewController(withIdentifier: "CEVC") as! EmailViewController {
self.dismiss(animated: false, completion: nil)
self.presentingViewController?.present(controller, animated: true, completion: nil)
}
}
You were trying to push a ViewVontroller from dismissing view controller,
and the answer which you have accepted is presenting a viewController from dismissing viewController. Although it may serve your purpose, but I am going to answer you original question
// get the object of presenting nanvigation controller(navigation controller with has presented this view controller)
let presentingNavigationController = presentingViewController?.navigationController
dismiss(animated: true) {
let cevc = self.storyboard?.instantiateViewController(withIdentifier: "CEVC") as! EmailViewController
// here you push your view controller with presentingNavigationController
presentingNavigationController?.pushViewController(cevc, animated: true)
}
Try to find out Navigation controller using below code and replace Viewcontroller with your Controller name.
let productVC = SeconViewViewController()
let parentVC = (parent!.presentingViewController as! ViewController).childViewControllers.first as! UINavigationController
self.navigationController?.dismiss(animated: true, completion: {
parentVC.pushViewController(productVC, animated: true)
})
I have two view controller
imag
1.first view controller is main and second is CustomAlertviw controller
main view controller is like above image, when I click continues am showing the customalertview controller, like image. when click the enter pin button I have to dismiss view contoller and show the view controller with uiview on main view controller but tried, it's showing the view controller, there one more custom view is not showing it crashing my app
main view code
#IBAction func backButtonClicked(_ sender: UIButton) {
let myAlert = UIStoryboard(name: "CustomAlertview", bundle: nil).instantiateViewController(withIdentifier: "CustomAlertViewController") as? CustomAlertViewController
myAlert?.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert?.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert!, animated: true, completion: nil)
}
Customalertview controller
#IBAction func enterPinButtonClick(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
let myAlert = UIStoryboard(name: "ScanAndPay", bundle: nil).instantiateViewController(withIdentifier: "ScanAndPayDetailsEntryViewController") as? ScanAndPayDetailsEntryViewController
myAlert?.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert?.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert!, animated: true, completion: nil)
myAlert.valuespass()
}
inside main view controller one function calling from the customalrerview
func valuespass()
{
DispatchQueue.main.async {
self.authType = 1
self.authStatus = false
print("this is calling")
self.pinStatusLabel.text = "Please enter a 4-digit Security PIN"
}
when I am calling this function from the custom alert view application is crashing and showing the hread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value this error. how to can show the all information after dismissing the custom view controller.
You are almost done. present ScanAndPay from FirstView instead of CustomAlertview.
I have done using Delegate as I think it will be fit in this scenario. Follow below steps -
Step 1:
In FirstViewController ,
Add - CustomAlertviewDelegate something like this -
class FirstViewController: UIViewController, CustomAlertviewDelegate {
Now replace your backButtonClicked method -
#IBAction func backButtonClicked(_ sender: UIButton) {
let myAlert = UIStoryboard(name: "CustomAlertview", bundle: nil).instantiateViewController(withIdentifier: "CustomAlertViewController") as? CustomAlertViewController
myAlert?.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert?.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
myAlert.delegate = self
self.present(myAlert!, animated: true, completion: nil)
}
Add a new Delegate method of CustomAlertviewDelegate -
func ScanAndPayView(){
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
let myAlert = UIStoryboard(name: "ScanAndPay", bundle: nil).instantiateViewController(withIdentifier: "ScanAndPayDetailsEntryViewController") as? ScanAndPayDetailsEntryViewController
myAlert?.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert?.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert!, animated: true, completion: nil)
}
}
Step 2:
Now time for CustomAlertview ,
Add protocol for delegate top of the Class -
protocol CustomAlertviewDelegate: class {
func ScanAndPayView()
}
class CustomAlertview: UIViewController{
weak var delegate : CustomAlertviewDelegate!
...
override func viewDidLoad() { // Rest of your code
}
Now time to dismiss current view controller and notify FirstViewController for presenting ScanAndPay view Controller -
#IBAction func enterPinButtonClick(_ sender: Any) {
delegate.ScanAndPayView()
self.dismiss(animated: true, completion: nil)
}
Hope it will help you to achieve what you want.
I'm trying to present a view controller and dismiss my current modal view. I saw the answers on StackOverflow, but I don't understand it.
self.dismissViewControllerAnimated(true, completion: {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("myViewController")
self.presentViewController(vc!, animated: true, completion: nil)
})
Could anyone please tell me, how to do it simply? Thanks
Check your main controller in stack and pop all other view controllers and then present new View Controller.
if let controllers = self.navigationController?.viewControllers {
for vc in controllers {
// Check if the view controller is of MainViewController type
if let myVC = vc as? MainViewController {
self.navigationController?.popToViewController(myVC, animated: false)
}
}
}
Push view controller :
let secondVC = self.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! SecondViewController
self.navigationController?.pushViewController(secondVC, animated: true)
or Present View Controller :
let next = self.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! SecondViewController
self.present(next as UIViewController, animated: true, completion: nil)
You can use this code to Present viewcontroller.
let yourVC = UIStoryboard(name: storyBord, bundle: nil).instantiateViewController(withIdentifier:ID) as! yourViewController
let navController = UINavigationController(rootViewController: yourVC)
self.present(navController, animated: true, completion: {
})
And for dissmissing use this in your presented viewController
self.dismiss(animated: true, completion: {
})
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")
}
}
}