App does not navigate to destination VC programmatically in swift - ios

I am trying to navigate from ConversationsListVC (source) to ConversationVC (destination) programmatically by instantiating the source VC (self) as the root navigation controller VC and then instantiating the destination VC so that I can push navigate.
I get the print statements onto the console (see below) but the app does not navigate to the destination VC, the app doesn't crash or throw any error. what am I missing here?
debug 1
debug 2
function:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("debug 1")
var window: UIWindow!
guard let convoVC = storyboard?.instantiateViewController(withIdentifier: "ConversationVC") as? ConversationVC else { return }
window?.rootViewController = UINavigationController(rootViewController: self)
navigationController?.pushViewController(convoVC, animated: true)
print("debug 2")
}//end func

try this one maybe the window instance is not correctly.
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "ConversationVC") as! ConversationVC
navigationController?.pushViewController(newViewController, animated: true)
and make sure your viewcontroller is assign with the Identifier

You can't just randomly create a new UINavigationController and push the destination onto it. You need to push the destination VC onto the UINavigationController in which self is currently embedded in.
If self is embedded in a UINavigationController already, do:
self.navigationController?.pushViewController(convoVC, animated: true)
If the source VC is not embedded in a UINavigationController, you need to do that in the storyboard.
Since you are using storyboards, you can also consider adding a push segue between the source and destination, and performing that segue:
self.performSegue(withIdentifier: "someIdentifier", sender: self)

Related

How to perform a segue from a pushed vc that has the segue defined in the storyboard

Here is the thing: my storyboard as a SettingViewController (after named SVC) and a StationsViewcontroller from which the latter is wired to a details view controller by the "openDetails" segue.
For practical reasons, my SVC can push several levels of specifics settings view controllers, which I did not defined in the storyboard.
At one point, one of those vc pushes the StationsViewController, which then can issue a performSegue to the detail: unfortunately, I get the "openDetails" segue is not defined.
What should I do to fix the issue?
--
The code has nothing peculiar, in the SettingsViewController, I push others VC, including the StationsViewController:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Gracefully remove the selection
tableView.deselectRow(at: indexPath, animated: true)
guard let section = MainSections(rawValue: indexPath.section) else { return }
switch section {
case .stations:
let vc = StationsViewController()
// Do no segue at dismiss
vc.onlyDismiss = true
vc.didDismiss = {
self.navigationController?.popViewController(animated: true)
}
push(vc, hideNavigation: true)
// Blah blah
And in the StationsViewController where I want to get to the details vc, I perform the segue:
func openPoiDetails(_ gs: GasStation) {
poiDetails = gs
performSegue(withIdentifier: "poiDetails", sender: nil)
// Blah blah
The storyboard is as follows, and we can see the StationsViewController on the left is wired to the details vc via the "openDetails" segue:
The problem is that your StationsViewController was just created from its initializer and the storyboard knows nothing about it. Therefore, you can't use the segue. Instead, you need to ask the storyboard to instantiate the StationsViewController:
Replace:
let vc = StationsViewController()
with:
let vc = self.storyboard?.instantiateViewController(withIdentifier: "StationsViewController") as! StationsViewController
Make sure you set the "StationsViewController" as the Storyboard ID in the Identify Inspector in Xcode.

Detect which viewController presented the SideMenu and implement proper functionality for its presentation

I'm using the following pod for my SideMenu functionality. Now, if I opened it from XYZ viewController and selected the row which again opens the XYZ viewController, the page is being pushed, but instead, I want the SideMenu to be dismissed, no to push already presented viewController.
Here is the UI:
And here is my didSelectRow code, which is quite clear:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.row {
case 0:
let playerVC = NavigationHelper.shared.getStoryBoard().instantiateViewController(withIdentifier: "mainPage") as? MainViewController
navigationController?.pushViewController(playerVC!, animated: true)
case 1:
let historyVC = NavigationHelper.shared.getStoryBoard().instantiateViewController(withIdentifier: "historyPage") as? BroadcastsHistoryViewController
navigationController?.pushViewController(historyVC!, animated: true)
case 2:
let sendMessageVC = NavigationHelper.shared.getStoryBoard().instantiateViewController(withIdentifier: "messagingPage") as? MessaginViewController
navigationController?.pushViewController(sendMessageVC!, animated: true)
case 3:
let settingsVC = NavigationHelper.shared.getStoryBoard().instantiateViewController(withIdentifier: "settingPage") as? SettingsViewController
navigationController?.pushViewController(settingsVC!, animated: true)
case 4:
let aboutVC = NavigationHelper.shared.getStoryBoard().instantiateViewController(withIdentifier: "aboutPage") as? AboutAppViewController
navigationController?.pushViewController(aboutVC!, animated: true)
default: break
}
}
So far I've tried to detect the topMost viewController, get the presentingViewController property, but had no success. Can anyone help me handle it in a proper way?
try adding var previousVC: UIViewController? to the sideMenu root view controller (lets call it SideMenuVC)
then on each view controller form where you will present the side menu from add
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let nextVC = segue.destination as? SideMenuVC {
nextVC.previousVC = self
}
}
then on the XYZViewController case write
if let vc = previousVC as? XYZViewController{
//dismiss sidemenu
} else {
//instantiate and push ViewController
}

I'm trying to create UIStoryboard but on error occurs in my code

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
let vc = storyboard?.instantiateViewController(withIdentifier: "vc1")as? DetailViewController
//vc?.image = img[indexPath.row]!
//vc?.name = imageArray[indexPath.row] storyboard
self.navigationController?.pushViewController(vc!, animated: true)
}
Error is:
Use of unresolved identifier 'storyboard'
Look into this:
// Case: When the next ViewController is existed in the same Storyboard.
let controller = self.storyboard?.instantiateViewController(withIdentifier: "ControllerIdentifier") as! YourViewController
// pass data here to the next controller.
self.navigationController?.pushViewController(controller, animated: true)
// Case: When the next ViewController is exists in other Storyboard.
let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "ControllerIdentifier") as! YourViewController
// pass data here to the next controller.
self.navigationController?.pushViewController(controller, animated: true)
Note: As you are using this line 'withIdentifier: "vc1"', I would like to suggest you that always assign the Storyboard ID for a ViewController same as ViewController's class name. Make it as a habit, it will be helpful because you don't need to remember the Storyboard Id what you set. So keep the thing simple.
Check in the properties of DetailViewController in Main.storyboard and see if the storyboard id is set properly. According to your code it should be vc1

performSegue from CollectionViewCell didSelectItemAt inside a navigation- and tabbarcontroller

I am going crazy as I can only get the modal popover working. My goal is to keep the destinationVC in both the navigation AND the tabbarcontroller.
As you can see from all my commented code, I have tried quite a lot. Some of code crash the app, others don't make an impact at all when I click the cell.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DestinationViewController : PlayEpisodeViewController = Storyboard.instantiateViewController(withIdentifier: "PlayEpisodeViewController") as! PlayEpisodeViewController
DestinationViewController.getEpisodeName = episodesArray[indexPath.row].EpisodeName
DestinationViewController.getEpisodeFileURL = episodesArray[indexPath.row].EpisodeURL
DestinationViewController.getEpisodeImage = episodesArray[indexPath.row].EpisodeImage
let navController = UINavigationController(rootViewController: DestinationViewController)
//UIApplication.shared.keyWindow?.rootViewController?.show(navController, sender: Any?.self)
//.pushViewController(DestinationViewController, animated: true)
UIApplication.shared.keyWindow?.rootViewController?.present(navController, animated: true, completion: nil)
//performSegue(withIdentifier: "playEpisodeSegue", sender: self)
//shouldPerformSegue(withIdentifier: String, sender: self)
//show(navigationController, sender: Any?.self)
//present(navigationController, animated: true, completion: nil)
}
Try to keep single responsibility principle, and incapsulate as much as possible inside you class. (i.e. avoid using UIApplication.shared.keyWindow?.rootViewController? etc.)
The easiest way to organise it using storyboard:
select you collection view controller, embed it into navigation controller, embed it into tab bar (or perhaps add "ViewControllers" Segue from tab bar controller to navigation controller)

pushViewController don't work when my tableView is in an TabBar

I have a TableViewController in a TabBar.
When I select one cell of my tableView, I want start a new controller with pushViewController(MyNewController).
This is my code :
In my TableView :
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myController = (storyboard.instantiateViewControllerWithIdentifier("MyViewController") as? MyViewController)!
myController.parameter = self.tableau[indexPath.row]
UINavigationController().pushViewController(myController, animated: true)
}
In my TabBar :
func viewDidLoad() {
super.viewDidLoad()
var controllerArray: [UIViewController] = []
let controller: UIViewController = ClubPreviewListViewController()
controller.title = "TEST"
controllerArray.append(controller)
self.view.addSubview(pageMenu!.view)
}
(I use CAPSPageMenu for customize my TabBar, but it's not the problem, I have the same problem without)
In my controller :
deinit {
print ("TEST")
}
When I select a cell, the log write "TEST" everytime I select but don't change the view.
I think it's my navigationController the problem, but I don't know how to fix it.
Before I implement the TabBar, I use my TableView alone, and the push did works.
Sorry for my english ! Thanks for your help.
EDIT:
I change my pushViewController :
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myController = (storyboard.instantiateViewControllerWithIdentifier("MyViewController") as? MyViewController)!
myController.parameter = self.tableau[indexPath.row]
//UINavigationController().pushViewController(myController, animated: true)
self.navigationController?.pushViewController(myController, animated: true)
}
Same reaction.
My NavigationController isn't directly link with my TabBar. I need to create an other one ? I don't really understand how NavigationController works !
This is my configuration
EDIT2:
If I use the navigationController of my TabBar and not of my TableView, the view change !
self.saveTabBarNavigationController.pushViewController(myController, animated: true)
You are creating an instance of a navigation controller on the line
UINavigationController().pushViewController(myController, animated: true)
Once this method finishes executing, the navigation controller and its view controllers will be deallocated because nothing retains your navigation controller. Causing 'TEST' to be printed in your deinit() function.
You should be obtaining the navigation controller that owns your current tab bar controller and pushing onto the stack using that. Without knowing the structure of your application it is difficult to know where your navigation controller is (if it exists).
Check your storyboard, but essentially try:
self.navigationController.pushViewController(myController, animated: true)
Try this it will work only if you have a navigation embedded tabbar controller
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let myController = (storyboard.instantiateViewControllerWithIdentifier("MyViewController") as? MyViewController)!
myController.parameter = self.tableau[indexPath.row]
navigationController.pushViewController(myController, animated: true)
}

Resources