Perform Segue from Another Class with Helper Function

Perform Segue from another class with helper function

You have to instantiated the storyBoard that you want then the TwelvethViewController and finally you can push.
Like this:

let storyBoard = UIStoryboard(name: "youStoryBoard", bundle: nil) 
let vc = storyboard?.instantiateViewController(withIdentifier: "youVCIndentifier") as! TwelvethViewController
self.navigationController?.pushViewController(vc, animated: true)

Perform Segue From Another Swift File via a class function

In order to perform a segue, you need the instance of view controller where the segue originates from - for example:

class MyViewController {
}

class MyClass {
showNextView(fromViewController: UIViewController) {
fromViewController.performSegueWithIdentifier("segue_id", sender: fromViewController)
}
}

However I discourage this kind of interaction. Don't tell the view controller how to show a view - let it do on its own, and just ask it.

So, I suggest creating an instance method in your view controller:

class MyViewController {
...
func goToNextView() {
performSegueWithIdentifier("segue_id", sender: self)
}
}

and use that to make the transition:

class MyClass {
showNextView(fromViewController: MyViewController) {
fromViewController.goToNextView()
}
}

How can i use uitableview cell for performing segue

Implement the UITableViewDelegate protocol method tableView(_:didSelectRowAt:) as below

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch sections[indexPath.row] {
case "Main Menu":
performSegue(with: "toMainMenu", sender: nil)
case "Settings":
performSegue(with: "toSettings", sender: nil)
case "Profile":
performSegue(with: "toProfile", sender: nil)
}
}

If you need to configure or pass some data to the destination controller, you can override the controller's prepare(for:sender:) method to get a reference, for example:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toMainMenu" {
let dvc = segue.destination as! MenuViewController
// now you have a reference
}
}

Issue with custom segue's perform method after firing performSegueWithIdentifier

I think it's because you're always performing the segue on the rootViewController and the segue is just calling presentModalViewController. A controller can only have 1 modal at a time; if you want to keep presenting modals you need to present them from the view controller at the top of the stack. I have no idea if that's what you mean to do.. it doesn't really make sense to keep showing modals unless you want to be able to pop backwards through the controller stack.

If you don't actually want the modals, you can just replace the rootViewController in your segue with the destination:

-(void) perform {
UIViewController *dst = (UIViewController *) self.destinationViewController;
// do some animation first
[[[UIApplication sharedApplication] delegate].window.rootViewController = dst;
}

It should also be noted that it is very weird to have a gesture recognizer on the app delegate like you mention in your question. It would make a lot more sense to implement your own UIViewController subclass that does the swipe handling and calls performSegueWithIdentifier: on itself.

Is it possible to define a generic unwind segue in the storyboard?

You cant have generic unwind segue. You cant inherit the storyboard properties of ViewController including the segue associated with ViewController. But you dont need a generic segue to solve your problem.

You can have a BaseViewController and all your other View Controllers will extend from BaseViewController. You can add your logic to verify if the user is still logged in in your BaseViewController (I cant write code for that as I have not seen your code base).

If the user is no longer logged in then you can simply call

class BaseViewController : UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
//implement your logic to monitor if user is still logged in if user not logged in simply call
self.logOut()
}

func logOut() {
//each child view controller will override and handle log out condition specifically for that ViewController
}
}

Finally to load the initial ViewController you can simply say pop all viewController on top of it. Assuming your initialViewController is rootViewController of your app you can simply modify your logic in BaseViewController as

   override func viewDidLoad() {
super.viewDidLoad()
//implement your logic to monitor if user is still logged in if user not logged in simply call
self.logOut()
UIApplication.shared.keyWindow?.rootViewController?.navigationController?.popToRootViewController(animated: true)
}

Issue with the approach:

Based on your question description I believe your initial view controller is kept in the ViewController stack and you simply unwind to that initial ViewController on logout.

Though this approach works, it has three issues

  1. Initial ViewController is unnecessarily kept in memory while it never reappears until user logs out, so you can actually get rid of it once user logs in and bring it back in once user logs out.

  2. If the user logs in and quits the app and restarts the app, app will load the initial View controller, but if the user is already logged in why would you even show initial view controller to him again??

  3. Because you are pushing other VCs on top of initial ViewController, that also means that user can simply keep hitting back button and come back to initial viewController which does not make sense, because how come user tapping on back button has anything to do with user logged in state ?? Isnt it??

Whats the better solution then ?

Change the root view controller of the app on app launch.

Open your AppDelegate and

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
//check if user is logged in

guard let window = UIApplication.shared.keyWindow else {
return
}

if (userIsLoggedIn) {
//load view controller that you wanna show after login lets say Home
let homeVC = //instantiate view controller from story board
UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations: {
window.rootViewController = homeVC
}, completion: { completed in
// maybe do something here
})
}
else {
//load initial controller
let initialVC = //instantiate view controller from story board
UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations: {
window.rootViewController = initialVC
}, completion: { completed in
// maybe do something here
})
}
}

Finally, if user isnt logged in and u end up loading initial VC and once user logs in your initial VC, you can use the code which I wrote above to change root VC

      let initialVC = //instantiate view controller from story board
UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations: {
window.rootViewController = initialVC
}, completion: { completed in
// maybe do something here
})


Related Topics



Leave a reply



Submit