UIPageViewController subviewcontroller can't perform segue on viewDidAppear - ios

I have a UIPageController which contains two subviewcontrollers. On start, I'm trying to perform a segue from SubViewControllerOne to LoginViewController when a user isn't authorized. I have a segue in viewDidAppear like so:
performSegue(withIdentifier: "authorizeSegue", sender: self);
This produces an unsuccessful segue and a warning
Warning: Attempt to present <Volley.LoginViewController: 0x7f98bd801e00> on <Volley.SubViewControllerOne: 0x7f98bd608400> whose view is not in the window hierarchy!
I've done this in the past with ViewControllers and TabBarViewControllers successfully.
When I wrap the segue in a timer, or trigger through an IBAction, the segue works perfectly fine. I believe it has something to do with the PageViewController.
class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate {
var subViewControllers = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
self.dataSource = self
self.edgesForExtendedLayout = [];
// Do any additional setup after loading the view.
let subViewControllerOne = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SubViewControllerOne") as! SubViewControllerOne
let subViewControllerTwo = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SubViewControllerTwo") as! SubViewControllerTwo
subViewControllers = [yourPodcastViewController, appearancesViewController]
setViewControllers([subViewControllers[0]], direction: .forward, animated: true, completion: nil)
}
required init?(coder: NSCoder) {
super.init(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
}
The navigation controller and PageViewController
The segue from SubViewControllerOne to LoginViewController

I think because of view controller life cycle you should perform segue into viewWillApear

Welp, I've had this issue before when running segues via didSelect on tableviews. The solution is to wrap it in the main thread. Not sure why this is necessary, but it solves my problem.
DispatchQueue.main.async {
self.performSegue(withIdentifier: "authorizeSegue", sender: self);
}

Related

Setting a viewController property by using a shared instance remains nil

I have two viewControllers:
1/ LoginViewController
2/ BibliothequeViewController
I am presenting BibliothequeViewController by clicking on a button inside LoginViewController and in the same time trying to communicate to BibliothequeViewController that it was LoginViewController that presented it.
So inside LoginViewController, I have this:
#IBAction func onLibrariesButtonClicked(_ sender: Any) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: BibliothequesViewController = storyboard.instantiateViewController(withIdentifier: "BibliothequesViewController") as! BibliothequesViewController
BibliothequesViewController.sharedInstance.presentedBy=self
print("INSIDE LoginViewController.onLibrariesButtonClicked, BibliothequesViewController.sharedInstance.presentedBy",BibliothequesViewController.sharedInstance.presentedBy!)
// Logs LoginViewController
self.present(vc, animated: true, completion: nil)
}
Inside BibliothequesViewController, I have this:
class BibliothequesViewController: UIViewController {
// presentedBy represents which view has presented the BibliothequesViewController
// So that when a library is selected, I go back to the ViewController that presented BibliothequesViewController
var presentedBy: UIViewController?
override func viewDidLoad() {
super.viewDidLoad()
print("INSIDE viewDidLoad, presentedBy: ",presentedBy)
// Logs nil
}
}
So as you see, in the LoginViewController code, BibliothequesViewController.sharedInstance.presentedBy has been set to LoginViewController.
But inside BibliothequeViewController, it is nil, when it should be LoginViewController.
I tried this:
print("INSIDE BibliothequesViewController, BibliothequesViewController.sharedInstance.presentedBy",BibliothequesViewController.sharedInstance.presentedBy!)
And I got LoginViewController logged. So I got what I needed.
But I expected the code above to work too.

Attempt to present UIImagePickerController on ViewController whose view is not in the window hierarchy

I'm in trouble, after that I'm moving from View Controller to a second View Controller and then switching back to the View Controller and clicking on the UI Image Picker it's not appearing and bringing me back to the second View Controller. On the debugger it's appearing:
Attempt to present on whose view is not in the window hierarchy!
I'm really becoming crazy. My code that is bringing me back from second View Controller to the first View Controller is inside a button and it's below:
#IBAction func profileButton(_ sender: Any) {
let webVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as! ViewController
webVC.profileLink = linkProfilo
self.present(webVC, animated: false, completion: nil)
}
in second view controller add this variable:
var firstVC: ViewController?
and this setter function to set it
setup(firstVC: ViewController) {
self.firstVC = firstVC
}
in the first view controller, when presenting second view controller pass in a reference to self (first view controller)by calling the setup function
let secondVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondViewController") as! ViewController
secondVC.setup(firstVC: self)
self.present(secondVC, animated: false, completion: nil)
now when button is clicked in secondVC,
guard let first = self.firstVC else {return}
first.profileLink = linkProfilo
self.dismiss(animated: false, completion: nil)
I finally found the way for fix all of this:
#IBAction func profileButton(_ sender: Any) {
if let webVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ViewController") as? ViewController {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
webVC.profileLink = linkProfilo
dismiss(animated: false, completion: nil)
appDelegate.window?.rootViewController!.present(webVC, animated: false, completion: nil)
}
}
it's enough to add the appDelegate sharing method and dismiss before to present the webVC for share the data in the right way and don't cause problems on the first view when presented.

using conditionals with presentingViewController in swift 3

I have some view controllers which are presenting another view controller like so:
class LikeDidTapViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Question") as? QuestionViewController {
if let navigator = navigationController {
navigator.pushViewController(viewController, animated: true)
}
}
}
}
In QuestionViewController I need to check which view controller presented it so I can use conditionals to perform various tasks. How can I accomplish this?

How to navigate To a ViewController From xib file of a UIView Class

I have a view in my xib file which contain buttons. i want to move to a ViewController when i will press the button (#IBAction). I have used below code
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("About") as! AboutViewController
self.presentViewController(nextViewController, animated: true, completion: nil)
I am getting the error "Value of type 'SlideMenuView' has no member 'presentViewController'.
because my class is a UIView type :
class SlideMenuView: UIView {
}
so how can I navigate to other view controller.
That is beacuase the class you are trying to present from is a UIView and not a UIViewController. It has no Present method.
I'm guessing your view (SlideMenuView) is embedded inside a viewcontroller. what you need to do is implement a delegate, and inform your containing viewController to present next Viewcontroller.
code below:
#protocol SlideMenuViewDelegate: class {
func slideMenuViewAboutButtonClicked(menuView: SlideMenuView)
class SlideMenuView: UIView {
weak var delegate: SlideMenuViewDelegate?
#IBAction func aboutButtonClicked(sender: AnyObject) {
self.delegate?.slideMenuViewAboutButtonClicked(self)
}
now, in your viewController, implement this delegate method:
func slideMenuViewAboutButtonClicked(menuView: SlideMenuView) {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("About") as! AboutViewController
self.presentViewController(nextViewController, animated: true, completion: nil)
}
Also, dont forget to assign the sliderMenuView object the viewcontroller as a delegate.
something like:
self.sliderMenuView.delegate = self // (self == the containing viewController
I did it in a different way. In class file
class SlideMenuView: UIView {
var navigationController: UINavigationController? // Declare a navigation controller variable
// And create a method which take a navigation controller
func prepareScreen(navController: UINavigationController)-> UIView {
navigationController = navController
let nibView = NSBundle.mainBundle().loadNibNamed("SlideMenuView", owner: self, options: nil)[0] as! UIView
self.addSubview(nibView)
return nibView
}
// In Button action
#IBAction func btnAction(sender: UIButton) {
var storyBoard = UIStoryboard(name: "Main", bundle: nil)
let nextViewController = storyBoard!.instantiateViewControllerWithIdentifier("NextViewController") as! UIViewController
navigationController?.pushViewController(nextViewController, animated: true)
}
}
// For calling from UIViewController
slideBarMenuIstance.prepareScreen(self.navigationController!)

Presenting view controller function not being called iOS Swift

For this problem, the view controller in which this code is run is in the Login.storyboard IB file. The view controller I am trying to present is in the Main.storyboard IB file. The code below is what I'm using to transition from one view controller to another.
func presentNextView() {
let mainSb: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let screenAfterLogin: UIViewController = mainSb.instantiateViewControllerWithIdentifier("MainContainerView") as! UIViewController
self.presentViewController(screenAfterLogin, animated: true, completion: nil)
}
Running the application, I set 3 breakpoints on the 3 lines executed in the presentNextView function. Line one is called, line two is called, but line three is NOT called, and the next screen is not presented. Is there something wrong with xCode at the moment?
Checkout the project on github: https://github.com/joshuarcher/RecallBeta
Problem lies in file "HardLoginViewController.swift"
func presentNextView() {
let mainSb: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let screenAfterLogin: SecondVC = mainSb.instantiateViewControllerWithIdentifier("SecondVC") as SecondVC
let navigationController = UINavigationController(rootViewController: screenAfterLogin)
presentViewController(navigationController, animated: true, completion: nil)
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
presentNextView()
}
func presentNextView() {
let mainSb: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let screenAfterLogin: SecondVC = mainSb.instantiateViewControllerWithIdentifier("SecondVC") as SecondVC
let navigationController = UINavigationController(rootViewController: screenAfterLogin)
presentViewController(navigationController, animated: true, completion: nil)
}
}
import UIKit
class SecondVC: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.title="Second Screen"
}
}

Resources