performSegue from CollectionViewCell didSelectItemAt inside a navigation- and tabbarcontroller - ios

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)

Related

App does not navigate to destination VC programmatically in swift

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)

How to dismiss previous view controller and move to next view controller in Swift iOS

in my application i am using a UITableView as a navigation menu for my app, it has 5 cells, 'Home', 'Order Online', 'Gallery', 'Contact', 'About'.
how it works is, when the user clicks the menu button the UITableView Menu pops down and then when a cell is clicked the correct UIViewController is loaded.
Now, the problem is, the previous view controller that was presented (before i move to a new controller via the tableView menu) is not dismissed. so in the app i can present the 'order online' view controller multiple times which obviously causes a memory problem,
BUT i do not want the view controller to be dismissed when it presents the tableView as i am using a custom transition where the tableview slides down half way down the screen so a snapshot of the previous controller should still be present, only when a cell is clicked in the tableView and a new view controller is presented, should the view controller loaded before the tableView be dismissed.
here is a screenshot of storyboard :
here are some screenshots:
here is all the 'relevant' code from my TableViewController that is used as the navigation menu:
class MenuTableViewController: UITableViewController {
var menuItems = ["Home", "Order Online", "Gallery", "Contact Us", "About"]
var currentItem = "Home"
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! MenuTableViewCell
// Configure the cell...
cell.titleLabel.text = menuItems[indexPath.row]
cell.titleLabel.textColor = (menuItems[indexPath.row] == currentItem) ? UIColor.white : UIColor.gray
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (indexPath.row == 0) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "homeView")
self.present(controller, animated: true, completion: nil)
}
if (indexPath.row == 1) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "orderView")
self.present(controller, animated: true, completion: nil)
}
if (indexPath.row == 2) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "galleryView")
self.present(controller, animated: true, completion: nil)
}
if (indexPath.row == 3) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "contactView")
self.present(controller, animated: true, completion: nil)
}
if (indexPath.row == 4) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "aboutView")
self.present(controller, animated: true, completion: nil)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let menuTableViewController = segue.source as! MenuTableViewController
if menuTableViewController.tableView.indexPathForSelectedRow != nil {
}
}
}
i have tried using
self.dismiss(animated: true, completion: nil)
in a number of ways but it just doesn't make the app work the way i want it to, any help will be appreciated.
In you didSelectRowAt method, you are instantiating a new instance of the view controller every time you are to present the new controllers.
You could simply instantiate them beforehand (perhaps within viewDidLoad) within your menuTableViewController, then reuse the same instances of the controllers. Doing this will also allow you to be able to dismiss them from the menuTableViewController class as it is holding references to each of the new Controllers.
If you are creating one, i suggest to use ONE custom navigation controller for the down menu + button, and it will control the content menu and vc, if you want to change it's root vc, just simply set vc of that custom navigation controller with self.setViewControllers([vc], animated: true), other vc will automatically dismiss itself

Tap on cell of UITableView and the other view doesn't appear

I have a tableView with some results of a search. I have connected the first and the second view with the "storyboard Segue" from the cell to the second view.
This is the code written in the first ViewController:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let indexPath = self.tableProva.indexPathForSelectedRow?.row
let vc = segue.destination as! DettaglioNewViewController
vc.titleLibro = posts[indexPath!].name
vc.authorLibro = posts[indexPath!].author
vc.ISBNLibro = posts[indexPath!].ISBN
}
In other project it works perfectly, but in this project it doesn't work, to show the second viewController I have to tap and swipe to the right or left.
It seems that the problem is graphic.
If I try to click on the cell does not become gray. turns gray if I hold down long on it
Has this happened to anyone else?
Can anyone help me?
You should use the 'didSelectRowAtIndexPath' method in order to segue to a different view for a specific cell. Use.....
var storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: NSBundle(forClass: self.dynamicType))
vc = storyboard.instantiateViewControllerWithIdentifier("LoginVC") as DettaglioNewViewController
vc.loadView()
..... To segue needed information.
* Information Example *
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
myFavIndex = indexPath.row
let storyBoard = UIStoryboard(name: "Main", bundle:nil)
let view = storyBoard.instantiateViewControllerWithIdentifier("LoginVC") as! DettaglioNewViewController
view.imageURL = self.imageArray[mySelectedIndex]
view.titleString = self.titleArray[mySelectedIndex]
self.presentViewController(view, animated: true, completion: nil)
}
In the above example I'm using the new View Controllers image and title as view.imageURL and view.titleString to populate that views elements from my selected Cells Information via [mySelectedIndex]. You should be able to do this with an Int, UIImage, String, e.g.
You don't need to initialize your controller from the code. Just create a custom segue and call 'performSegue' method in 'didSelect' method of table delegate.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
self.performSegueWithIdentifier("yourIdentifierInStoryboardForCustomSegue", sender: nil)
}

pushViewController does no action

i have a tableview and i want to go to another vc when one of rows tapped. my didSelectRowAtIndexPath function is as below. print command works and shows the right clicked row. but when i use self.navigationController?.pushViewController it does not go to vc with playVideo storyBoardId. after changing it to presentViewController it works. what's wrong about my code that push doesn't work?
thanks
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("clicked " + String(indexPath.row) )
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("playVideo") as! PlayVideoViewController
vc.id = self.video[indexPath.row].id
// Present View as Modal
//presentViewController(vc as UIViewController, animated: true, completion: nil)
// Push View
//self.navigationController?.pushViewController(vc, animated: true)
}
Its because the view controller you are currently in may not have a navigation controller.
You cannot push a view controller without having a UINavigationController.
If your requirement is to push a view controller, then perform the following steps.
Embed a navigation controller for the current view controller.(Open storyboard -> Choose your view controller -> Choose "Editor" -> "Embed in" -> UINavigationController)
Now your code
self.navigationController?.pushViewController(vc, animated: true)
will be working fine.
Make sure that your ViewController is indeed built on a NavigationController. Try forcing the line:
self.navigationController!.pushViewController
if it crashes, you know there is not nav set up. Or you could just check in your storyboard but this is a quick way to tell.
I dont know why are you doing it like this. I think its unnecessarily complicated.
This should by your function didSelectRowAtIndexPath:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("playVideo", sender: tableView)
}
Then you can specify as much segues as you want in this function:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "playVideo") {
let indexPath:NSIndexPath = tableView.indexPathForSelectedRow!
let PlayVideoViewController = segue.destinationViewController as! PlayVideoViewController
//you can pass parameters like project id
detailVC.projectID = ids[indexPath.row]
}
}
Your segue has to be named like this in interface builder:

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