Present modal while transitioning to the previous view - swift

When I leave a particular view controller, I want to have it display a modal view over the previous view in the navigation stack. Currently I'm doing it with this code:
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.viewControllers.last?.present(myModalView, animated: false, completion: nil)
}
This seems to work, but every time I leave the view I get a warning in the console:
Presenting view controllers on detached view controllers is discouraged <Project.MyViewController: 0x7fe09281a400>.
So I'm concerned that there might be a problem I haven't run into yet. Is there a "correct" way of doing this?

As it turns out, self.present(myModalView, animated: false, completion: nil) works perfectly with no warnings. In retrospect, I probably should have tested that first, but I had assumed it wouldn't work since the view was disappearing.
Additionally, it does not work at all with animated: true, whereas my original solution does with no warnings (but I don't want it to be animated). Not sure if that's just how the asynchronous processes work out or if there's something more to it.

You are presenting the modal on the current view controller, not over the previous view controller. When you do
self.navigationController?.viewControllers.last?.present(myModalView, animated: false, completion: nil)
in the viewWillDisappear protocol, it's the same as saying
self.present(myModalView, animated: false, completion: nil)
Instead, try this:
let previousVCIndex = self.navigationController?.viewController.index(of: self)
self.navigationViewController?.viewControllers[previousVCIndex! - 1]?.present(myModalView, animated: false, completion: nil)

Related

How to dismiss GKTurnBasedMatchmakerViewController from SKScene

How do you dismiss the GKTurnBasedMatchmakerViewController once a match is created? The available delegates seems to be only for when there is an error. There used to be one called didFind, but since its deprecated, I am struggling to figure out how to dismiss it once match is created or when player Taps on an existing match.
receivedTurnEventFor is the only follow up call and it has no reference to the match maker view controller.
I am loading GKTurnBasedMatchmakerViewController on an SKView via
let viewController = self.view?.window?.rootViewController
let vc = GKTurnBasedMatchmakerViewController(matchRequest: r)
vc.turnBasedMatchmakerDelegate = self
viewController?.present(vc, animated: true, completion: {
print("launched GKTurnBasedMatchmakerViewController")
})
Just add
self.presentedViewController?.dismiss(animated: true, completion: nil)
in player(_:receivedTurnEventFor:didBecomeActive:)

App crashing when instantiating ViewController from different storyboard

I'm writing in Swift 3 (latest Xcode)
I'm controlling, if the user is logged in (async tasks checking parameters between device and database).
If the response says, that the device is invalid, I'm showing the login screen. Looks like this:
extension UIViewController {
func forceLogin() {
let storyboard = UIStoryboard(name: "Login", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "LoginViewController")
let navController = UINavigationController(rootViewController: controller)
self.present(navController, animated: true, completion: nil)
}
}
Login storyboard looks just like this.
When user successfully logs in, the function starts:
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
}
The dismissal may happen in first and second ViewController.
Imagine the situation:
User logs in and comes back to main application after dismissing 2nd VC
Device is being deleted from DB
After check, user needs to log in again
forceLogin() and...
libc++abi.dylib: terminating with uncaught exception of type NSException
It happens when self.present(navController, animated: true, completion: nil) is used.
I have some ideas what may cause the crash but I'm not sure:
Creating navigation controller in code instead in storyboard
Dismiss is not enough - storyboard somehow stays in memory and can't be instantiated again
What can cause the problem and how can I avoid crashing?
If any more info is necessary, please ask.
I always forget this. Remeber to place your interface tasks like this:
DispatchQueue.main.async {
self.present(navController, animated: true, completion: nil)
}

Go to next Page in UIPageViewController

I have a button and I just want to go to the next page.
I have read in other threads people saying to just used this,
setViewControllers([UIVIewController], direction: .forward, animated: false, completion: nil)
I have tried this in the button on a child view. I see that the PageControl (the little dots) has the functionality I want but I can't seem to find how apple implemented this. I have been reading a lot of posts on stackOverflow but I am not quite grasping it.
I have a rootViewController that implements the dataSource and delegate.
First get the current view controller and next view controller and then pass the next view controller in setViewControllers function
func moveToNextPage() {
guard let currentViewController = self.viewControllers?.first else { return print("Failed to get current view controller") }
guard let nextViewController = self.dataSource?.pageViewController( self, viewControllerAfter: currentViewController) else { return }
setViewControllers([nextViewController], direction: .forward, animated: false, completion: nil)
}
I hope this helps you.

Swift viewWillAppear redirect

I'm using "viewWillAppear" to check UserDefaults.standard if i have data on the defaults i want redirect to Dashboard View and pass out of Login.
When i Log In correctly the app redirect normally but not in viewWillAppear in case of have data.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let defaults = UserDefaults.standard
if defaults.string(forKey: "username") != nil {
print("Exist")
print(defaults.string(forKey: "username")!)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "Dashboard")
self.present(vc, animated: true, completion: nil)
}
}
And i get this error con debug.
2016-11-04 17:44:32.130024 RHiOS[1155:278240] Warning: Attempt to present <RHiOS.MenuViewController: 0x100f0d480> on <RHiOS.ViewController: 0x100e0b880> whose view is not in the window hierarchy!
How can i redirect to Dash in case of have data? Thanks.
You cannot present a ViewController in viewWillAppear. Simply put this code in viewDidAppear and it should fix your problem.
When the view is not visible, it's not in the window hierarchy as the error mentioned. You could also create a segue in your storyboard and call performSegue(withIdentifier:sender:) instead.
You won't be able to present anything when the view hasn't appeared yet, so you either have to move your code into viewDidAppear or prevent this view from showing in the first place and redirect directly to the dashboard from a parent view controller that presents either the dashboard or login screen depending on whether or not you have data.

how to present UIViewController from SKScene

Usaly when you present a viewController from another viewController you do:
let vc : UIViewController = storyboard.instantiateViewControllerWithIdentifier("viewController") as UIViewController;
self.presentViewController(vc, animated: true, completion: nil);
I want to present a viewController from a SKScene. I haven't found any way of doing that.
This question might be a duplicate, but i have just found answers in objective C that doesn't make sense to me
Try the following in your scene class:
var currentViewController:UIViewController=UIApplication.sharedApplication().keyWindow.rootViewController!
currentViewController.presentViewController(viewController, animated: true, completion: nil)
I hope it helps.