How to navigate back to correct previous viewController - swift3

Hi I have the following scenario:
|---> VC1----->|
VC_Home ->|---> VC2----->|------> VCm
|---> VC3----->|
VC1, VC2 and VC3 can go to the same ViewController (VCm)
How to navigate back to the correct Previous VC from VCm
if I start from VC1 and go to VCm, then Vcm will return to VC1.
So, the same for VC2 and VC3.
all VC1, VC2, VC3 dont embed with NavigationController.
will this be able to identify which is the previous page?
#IBAction func goBack(_ sender: Any){
navigationController?.popViewController(animated: true)
}
Please help.
Thanks

Add UINavigationController in your storyBoard
Add new UIViewController [which is VC_HOME] and link it with UINavigationController as root View Controller (ctrl + drag)
Give it an ID (right utilities view -> Identity Inspector -> StoryBoard ID -> Name it "myHome")
Add 3 button [go to vc1, go to vc2, go to vc3] and of course add #IBAction for each of them
Add 3 different UIViewController for vc1, vc2, vc3 and like step 3 give them IDs myVc1, myVc2, myVc3
Now for #IBAction go to vc1 add following code :
let view = storyboard!.instantiateViewController(withIdentifier: "myVc1")
navigationController?.pushViewController(view, animated: true)
for #IBAction go to vc2 add following code :
let view = storyboard!.instantiateViewController(withIdentifier: "myVc2")
navigationController?.pushViewController(view, animated: true)
for #IBAction go to vc3 add following code :
let view = storyboard!.instantiateViewController(withIdentifier: "myVc3")
navigationController?.pushViewController(view, animated: true)
Now for each view add button go to VC_M like steps above
for back to previous viewController [vc1, vc2, vc3] use this code :
navigationController?.popViewController(animated: true)
if you back to the root [VC_Home] use this : navigationController?.popToRootViewController(animated: true)

just dismiss you final view controller. add following to you back action in your final view controller.
dismiss(animated: true, completion: nil)

Related

How to start view controller from non viewcontroller class

I want to open present uiviewcontroller from class that inherts from nsobject .how this work?
I tried this code
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "LoginSignupVC")
self.present (initialViewController, animated: false, completion: nil)
In your code self.present wont work because you're inside a NSObject class.
So self refers to NSObject class.
NSObject class doesn't have a method present in it.
For presenting a view controller you must have a navigation controller as root.
Solution 1: So get the navigation controller using self.navigationController and present your view controller to it.
let initialViewController = self.storyboard!.instantiateViewControllerWithIdentifier("LoginSignupVC") as! ViewController
self.navigationController!.presentViewController(initialViewController, animated: true)
Solution 2: Create a navigationcontroller manually and present in it.
let initialViewController = self.storyboard!.instantiateViewControllerWithIdentifier("LoginSignupVC") as! ViewController
let navController = UINavigationController(rootViewController: initialViewController)
self.presentViewController(navController, animated:true, completion: nil)

Snapshotting a view that has not been rendered results in an empty snapshot when view presented modally - Swift 3

I have a Table View Controller as a tab. In it, there's a button that takes you to a Facebook profile:
func didTapFacebook() {
let url = URL(string: "http://www.facebook.com/" + myFacebookId)
if UIApplication.shared.canOpenURL(url!) {
UIApplication.shared.open(url!, options: [:], completionHandler: nil)
}
}
Works fine every time you press the button.
From another tab, there's a button that presents modally a navigation controller with Table View Controller as its root:
func segueToTable(_ sender: UIViewController, tvc: MyTableViewController, completion: #escaping ((_ done: Bool) -> Void)) {
let nc = MyNavigationController(rootViewController: tvc)
sender.present(nc, animated: true, completion: {
completion(true)
})
}
…
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tvc = storyboard.instantiateViewController(withIdentifier: "TVC") as! MyTableViewController
segueToTable(self, tvc: tvc, completion: { done in
print(“segue complete”)
})
Now once you tap the same button to go to Facebook profile (or Twitter button, basically anything that causes the app to go to background), this warning occurs (there is no keyboard displayed on the screen at this time):
Cannot snapshot view (>) with afterScreenUpdates:NO, because the view is not in a window. Use afterScreenUpdates:YES.
Returning to the app and pressing the button again causes this warning to appear (and every attempt after that):
Snapshotting a view that has not been rendered results in an empty snapshot. Ensure your view has been rendered at least once before snapshotting or snapshot after screen updates.
I realize this is related to snapshotting a view that automatically occurs prior to entering the background. It appears for some reason it doesn't like doing that within a view that was presented modally. I've tried a variety of things based on other posts but cannot get the warnings to go away.
Any help is appreciated.

How to change the way in which the root controller of a navigation controller is appearing on screen?

The navigation controller is not the initial view controller. It is being instantiated in the initial VC and supplied with a root controller, the second VC. When I call present view controller function I cannot change the way in which this new VC in being presented, it always appears from the bottom. I did not find how to make it come from right to left. I tried to change who gets the call to modalPresentaionStyle from the second VC to the nav con and back but no change.
Code listing below. Thank you for your help.
#objc fileprivate func showRegisterScreen() {
let registerAccountVC = RegisterAccountVC()
let navigationController = UINavigationController(rootViewController: registerAccountVC)
navigationController.modalPresentationStyle = .pageSheet
present(navigationController, animated: true, completion: nil)
}
This will add a custom animation from right to left.
let transition = CATransition.init()
transition.duration = 0.4
transition.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromRight
view.window?.layer.add(transition, forKey: nil)
present(navigationController, animated: false, completion: nil)

Can't push from programmatically created UINavigationController

In a Swift 3 project using Xcode 8.3 and iOS 10.3, I get a navigation controller to push. The app runs with a navigation controller until I try to use it to push. All works until the last line which cause an app crash, fatal error: unexpectedly found nil while unwrapping an Optional value. I don't want to use the storyboard, the point of this question is how to accomplish this task without the storyboard.
App Delegate code
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = UINavigationController(rootViewController: MainViewController())
}
View Controller:
import UIKit
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let navController = navigationController
let myProfileViewController = MyProfileViewController()
navController!.pushViewController(myProfileViewController, animated: true)
}
}
Move
let navController = navigationController
let myProfileViewController = MyProfileViewController()
navController!.pushViewController(myProfileViewController, animated: true)
from viewDidLoad to viewDidAppear.
In viewDidLoad there is no parent navigation controller set up and you should not start animations from there.
You can add navigation controller in storyboard,
in Storyboard click on MainViewController & from editor menu add navigation controller & push via navigation controller as below code.
let vc = self.storyboard?.instantiateViewController(withIdentifier: "MyProfileViewController") as! MyProfileViewController
self.navigationController?.pushViewController(vc, animated: true)
Make sure storyboard identifier is correct. & remove navigation controller code form AppDelegate class.
first give name to your navigation controller like this
then in your code initialise it like this
let nav = (UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "yourNavigation") as! UINavigationController);
nav.pushFrontViewController(MainViewController(), animated: true);
window?.rootViewController = nav

Automatic presenting View Controller

I have 2 view controllers on my storyboard: viewController1(it input point) and viewController2. After loading the application i want to automatic presenting viewController2 after viewController1.
How i can do that?
if you want to go to second viewcontroller you can add this code to you viewDidLoad method:
let secondViewController = self.storyboard?.instantiateViewController(withIdentifier: "yourIdentifier") as! secondViewController
self.navigationController?.pushViewController(secondViewController, animated: true)
remeber to add a identifier for the second viewcontroller in storyboard and chenge the identifier that you use with "yourIdentifier"
if you don't want a animation put the animated: true to false.
if you dont want to show the fist viewcontroller, go into you storyboard and click on the second viewcontroller, then in the right side on attributes inspector select the box int the image:
For change viewcontroller you have to embed the first viewcontroller with a navigation controller, if you don't know how to do it, just select the fisrt viewcontroller and do like the image, click in navigation controller
Have you tried to show it in func viewDidLoad() {} like:
override func viewDidLoad() {
// ...
self.present(viewController, animated: true, completion: nil)
}
If you want to straight up load a different view controller you can do this in your app delegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "put your identifier here")
self.window?.rootViewController = vc
return true
}