Issue using delegate method to poptoviewcontroller | Swift 5 - ios

I have the following delegate method that I activate on dismiss of a .formsheet - when it dismisses I need to popToViewController - it appears print("User Logged Out") is also not printing, what is being done incorrectly? I am primarily instructed in how to do this using delegates if possible.
View Controller 2
var delegate: LogoutDelegate?
func logout() {
print("Logout")
self.delegate?.didLogout()
dismiss(animated: true, completion: {
})
}
View Controller 1
protocol LogoutDelegate {
func didLogout() -> Void
}
func didLogout() -> Void {
print("User Logged Out")
self.navigationController?.popToRootViewController(animated: true)
}
Presenting ViewController2:
let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Test") as! SettingsViewController
let navigationController = UINavigationController(rootViewController: controller)
navigationController.modalPresentationStyle = .formSheet
self.present(navigationController, animated: true, completion: nil)

Assuming your ViewController2 is SettingsViewController, when you are preparing to present ViewController2, you need to set its delegate to your current viewController viewController1.
Sth like this:
let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Test") as! SettingsViewController
controller.delegate = self
let navigationController = UINavigationController(rootViewController: controller)
navigationController.modalPresentationStyle = .formSheet
self.present(navigationController, animated: true, completion: nil)
Again, I'm assuming this code is in your VC1, so in this case self is your VC1.

Related

how to present and dismiss at same time

This is my Code
#IBAction func backButton(_ sender: UIButton) {
self.dismiss(animated: true, completion: { () -> Void in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "RequestItemPackageDetails") as! RequestItemPackageDetails
self.present(vc, animated: true, completion: nil)
})
}
this is not working only dissmising
I dont't understand your questions well. I think you want to present a new ViewController. You can use this:
UIView.animate{duration: 0.5, animations: {
(UIApplication.shared.delegate as! AppDelegate).window!.rootViewController = NextViewController()
}}
Problem is that you are dismissing self and then trying to present a new view controller on that exact same self - but at that moment self is already dismissed. You need to present that new view controller from the parent of the current view controller. I believe the best way is to setup a delegate. So the controller that you showed us and that you want to dismiss will have this:
protocol FirstDelegate: class {
func firstDismiss(_ first: First)
}
class First: UIViewController {
weak var delegate: FirstDelegate?
#IBAction func backButton(_ sender: UIButton) {
// this will tell the delegate to dismiss this contorller and present the other one
delegate?.firstDismiss(self)
}
// rest of the code omitted
}
Next, you will have to setup this in the parent that presents First view controller (here I assume that presentFirst method presents the First view controller):
class ParentViewController: UIViewController, FirstDelegate {
// rest of the code
func presentFirst() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let firstVC = storyboard.instantiateViewController(withIdentifier: "First") as! RequestItemPackageDetails
// set delegate to first:
firstVC.delegate = self
self.present(firstVC, animated: true, completion: nil)
}
func firstDismiss(_ first: First) {
first.dismiss(animated: true, completion: { () -> Void in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "RequestItemPackageDetails") as! RequestItemPackageDetails
self.present(vc, animated: true, completion: nil)
})
}
}
Not quite sure with your Qns, but try this one out.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "RequestItemPackageDetails") as! RequestItemPackageDetails
vc.previousVC = self
self.present(vc, animated: true)
RequestItemPackageDetails.swift
var previousVC : UIViewController!
override viewDidLoad() {
previousVC.dismiss(animated: false, completion: nil)
}
You can dismiss self and then present another view from rootViewController
self.dismiss(animated: true, completion: { () -> Void in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "RequestItemPackageDetails") as! RequestItemPackageDetails
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window!.rootViewController?.present(vc, animated: true, completion: nil)
})

How do I force a ViewController to present without the user pressing any buttons?

When a function is called, I would like SixthViewController to be presented to the user without the user needing to press any buttons. I know how to present another ViewControllerby setting a button to "Show" another ViewController, but how can I programmatically force SixthViewController to present itself once the function is called?
you can present viewcontroller with this way:
let destVC = SixthViewController()
self.present(destVC, animated: true, completion: nil)
or
let storyboard: UIStoryboard = UIStoryboard(name: "storyboardNamehere", bundle: nil)
let destVC = self.storyboard?.instantiateViewController(withIdentifier: "ViewControllerIdentifierhere" as! SixthViewController
self.present(destVC, animated: true, completion: nil)
========================================================================
just write down this function and also called it when u want to push or write down it in any function like func pushViewController and called it self.pushViewController() that's it bro.
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let sixthViewController = storyBoard.instantiateViewController(withIdentifier: "SixthViewController") as! SixthViewController
self.navigationController?.pushViewController(sixthViewController, animated: true)
If you are not using segues but navigation controller try this:
let destinationVC = SixthViewController()
self.navigationController?.pushViewController(destinationVC, animated: true)
If you just want to show it without navigation controller:
let destinationVC = SixthViewController()
self.present(destinationVC, animated: true, completion: nil)
If you are using storyboard:
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let destVC = self.storyboard?.instantiateViewController(withIdentifier: "SixthViewController" as! SixthViewController
self.present(destVC, animated: true, completion: nil)

Dismiss Login Screen in iOS when using Parse

override init() {
super.init()
parseLoginHelper = ParseLoginHelper {[unowned self] user, error in
// Initialize the ParseLoginHelper with a callback
if let error = error {
// 1
ErrorHandling.defaultErrorHandler(error)
} else if let _ = user {
// if login was successful, display the TabBarController
// 2
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewControllerWithIdentifier("TabBarController")
// 3
self.window?.rootViewController!.presentViewController(tabBarController, animated:true, completion:nil)
}
}
}
So I understand that the code here should be able to replace my login screen upon hitting login, however, it does not. Instead it loads and stays on the login screen for parse. However, if I exit the app, it loads the proper screen. Does anyone have any ideas how to dismiss login screen more efficiently upon login?
let user = PFUser.currentUser()
let startViewController: UIViewController;
if (user != nil) {
// 3
// if we have a user, set the TabBarController to be the initial view controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
startViewController = storyboard.instantiateViewControllerWithIdentifier("TabBarController") as! UITabBarController
} else {
// 4
// Otherwise set the LoginViewController to be the first
let loginViewController = PFLogInViewController()
loginViewController.fields = [.UsernameAndPassword, .LogInButton, .SignUpButton, .PasswordForgotten]
loginViewController.delegate = parseLoginHelper
//loginViewController.signUpController?.delegate = parseLoginHCelper
startViewController = loginViewController
}
// 5
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window?.rootViewController = startViewController;
self.window?.makeKeyAndVisible()
return false
}
I believe you should not call
self.window?.rootViewController!.presentViewController(tabBarController, animated:true, completion:nil)
instead if you already in some controller why just go to tabBar like that:
presentViewController(tabBarController, animated:true, completion:nil)
You should not use :
self.window?.rootViewController!.presentViewController(tabBarController, animated:true, completion:nil)
Try to change that line by :
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("tabBarController") as! tabBarController
self.presentViewController(vc, animated: true, completion: nil)
and in your storyboard, set the storyboard id of tabBarController under identity inspector to : tabBarController

How to get Current viewcontroller (currently Presenting) using storyboard id in swift programmatically?

**How to get the presenting view controller in swift. I am using storyboard id.**And for presenting next viewcontroller how can I add to the hierarchy?
I tried like this:
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let logincontroller = mainStoryboard.instantiateViewControllerWithIdentifier("LoginViewController")
if UIApplication.sharedApplication().keyWindow?.rootViewController.presentingViewController == logincontroller {
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let nextVC = mainStoryboard.instantiateViewControllerWithIdentifier(storayboardIdentifier)
self.presentViewController(nextVC, animated: true, completion: nil)
}
In Appdelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
if isLoggedin == false {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
else {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
}
The code works, it display the view but it still have a warning
Failed to instantiate the default view controller for
UIMainStoryboardFile 'Main' - perhaps the designated entry point is
not set?
Check initial entry points.
Also to present screen below code practice is better way.
let objNextViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ID_NextViewController") as? ViewController
self.presentViewController(objNextViewController, animated: true) { () -> Void in
print("Achive")
}
EDITED :
If you want to present viewcontroller from already presented view controller then use below code.
var currentViewController : UIViewController!
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
if let viewControllers = appDelegate.window?.rootViewController?.presentedViewController
{
self.currentViewController = viewControllers as UIViewController
}
else if let viewControllers = appDelegate.window?.rootViewController?.childViewControllers
{
self.currentViewController = viewControllers.last! as UIViewController
}
let objNewViewController : NewViewController!
self.currentViewController.presentViewController(objNewViewController!, animated: true, completion: { () -> Void in
NSLog("Achived")
})
try this code for presentingViewControllerusing storyboard name:
let viewController:UIViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("ViewController") as UIViewController
self.presentViewController(viewController, animated: false, completion: nil)
try this code,
let storyboard : UIStoryboard = UIStoryboard(name:"Main", bundle: nil)
let vc : WelcomeViewController = storyboard.instantiateViewControllerWithIdentifier("WelcomeID") as WelcomeViewController
let navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
hope its helpful
My guess is that you haven't set an initial view controller for your storyboard.
To fix this open your storyboard and select the UIViewController you want to display as the first one. Then in the Attributes inspector tab(third one from the right in the utilities panel), look under the View Controller section and make sure the Is Initial View Controller checkbox is checked.

How to Navigate from one View Controller to another using Swift

I'd like to navigate from one view controller to another. How can I convert the following Objective-C code into Swift?
UIViewController *viewController = [[self storyboard] instantiateViewControllerWithIdentifier:#"Identifier"];
UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:viewController];
[self.navigationController pushViewController:navi animated:YES];
Create a swift file (SecondViewController.swift) for the second view controller
and in the appropriate function type this:
let secondViewController = self.storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as SecondViewController
self.navigationController.pushViewController(secondViewController, animated: true)
Swift 2+
let mapViewControllerObj = self.storyboard?.instantiateViewControllerWithIdentifier("MapViewControllerIdentifier") as? MapViewController
self.navigationController?.pushViewController(mapViewControllerObj!, animated: true)
Swift 4
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "IKDetailVC") as? IKDetailVC
self.navigationController?.pushViewController(vc!, animated: true)
In my experience navigationController was nil so I changed my code to this:
let next = self.storyboard?.instantiateViewControllerWithIdentifier("DashboardController") as! DashboardController
self.presentViewController(next, animated: true, completion: nil)
Don't forget to set ViewController StoryBoard Id in StoryBoard -> identity inspector
If you don't want the back button to appear (which was my case, because I wanted to present after a user logged in) here is how to set the root of the nav controller:
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("YourViewController") as! YourViewController
let navigationController = UINavigationController(rootViewController: vc)
self.presentViewController(navigationController, animated: true, completion: nil)
SWIFT 3.01
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "Conversation_VC") as! Conversation_VC
self.navigationController?.pushViewController(secondViewController, animated: true)
In swift 4.0
var viewController: UIViewController? = storyboard().instantiateViewController(withIdentifier: "Identifier")
var navi = UINavigationController(rootViewController: viewController!)
navigationController?.pushViewController(navi, animated: true)
In Swift 4.1 and Xcode 10
Here AddFileViewController is second view controller.
Storyboard id is AFVC
let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)
//OR
//If your VC is DashboardViewController
let dashboard = self.storyboard?.instantiateViewController(withIdentifier: "DBVC") as! DashboardViewController
self.navigationController?.pushViewController(dashboard, animated: true)
If required use thread.
Ex:
DispatchQueue.main.async {
let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)
}
If you want move after some time.
EX:
//To call or execute function after some time(After 5 sec)
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
let next = self.storyboard?.instantiateViewController(withIdentifier: "AFVC") as! AddFileViewController
self.present(next, animated: true, completion: nil)
}
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let home = storyBoard.instantiateViewController(withIdentifier: "HOMEVC") as! HOMEVC
navigationController?.pushViewController(home, animated: true);
Swift 3
let secondviewController:UIViewController = self.storyboard?.instantiateViewController(withIdentifier: "StoryboardIdOfsecondviewController") as? SecondViewController
self.navigationController?.pushViewController(secondviewController, animated: true)
In swift 3
let nextVC = self.storyboard?.instantiateViewController(withIdentifier: "NextViewController") as! NextViewController
self.navigationController?.pushViewController(nextVC, animated: true)
let objViewController = self.storyboard?.instantiateViewController(withIdentifier: "ViewController") as! ViewController
self.navigationController?.pushViewController(objViewController, animated: true)
Swift 5
Use Segue to perform navigation from one View Controller to another View Controller:
performSegue(withIdentifier: "idView", sender: self)
This works on Xcode 10.2.
Swift 4
You can switch the screen by pushing navigation controller first of all you have to set the navigation controller with UIViewController
let vc = self.storyboard?.instantiateViewController(withIdentifier: "YourStoryboardID") as! swiftClassName
self.navigationController?.pushViewController(vc, animated: true)
In AppDelegate you can write like this...
var window: UIWindow?
fileprivate let navigationCtrl = UINavigationController()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
self.createWindow()
self.showLoginVC()
return true
}
func createWindow() {
let screenSize = UIScreen.main.bounds
self.window = UIWindow(frame: screenSize)
self.window?.backgroundColor = UIColor.white
self.window?.makeKeyAndVisible()
self.window?.rootViewController = navigationCtrl
}
func showLoginVC() {
let storyboardBundle = Bundle.main
// let storyboardBundle = Bundle(for: ClassName.self) // if you are not using main application, means may be you are crating a framework or library you can use this statement instead
let storyboard = UIStoryboard(name: "LoginVC", bundle: storyboardBundle)
let loginVC = storyboard.instantiateViewController(withIdentifier: "LoginVC") as! LoginVC
navigationCtrl.pushViewController(loginVC, animated: false)
}
For Swift 4 & 5 Users can use this way
Swift 5
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
self.navigationController?.pushViewController(vc, animated: true)
Swift 4
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "YourViewController") as? YourViewController
self.navigationController?.pushViewController(vc!, animated: true)
Better practices Swift 5.0
More reusable and readable
Create a protocol
protocol Storyboarded { }
Now create an extension of the protocol
extension Storyboarded where Self: UIViewController {
static func instantiateFromMain() -> Self {
let storyboardIdentifier = String(describing: self)
// `Main` can be your stroyboard name.
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
guard let vc = storyboard.instantiateViewController(withIdentifier: storyboardIdentifier) as? Self else {
fatalError("No storyboard with this identifier ")
}
return vc
}
}
// Make a ViewController extension to use on all of your ViewControllers
extension UIViewController: Storyboarded {}
How to use
let vc = MyViewController.instantiateFromMain()
//here you can pass any data to the next view controller. for example we have a variable with name `myString` in our next view contoller and we want to pass the data my `self viewController`
vc.myString = "This string passed by MyViewController"
self.navigationController?.pushViewController(vc, animated: true)
Note:- You need to give the same identifier on the storyboard as your UIViewController class has. Check the example below
Update for Swift 5:
let next = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.present(next, animated: true, completion: nil)
Don't forget to update the Storyboard ID for both View Controllers!

Resources