Create and perform segue without storyboards - ios

i got an app without storyboards, all UI creation is made in code and I got a splitView which I would make it usable on iPhone, because as the app as been first designed for iPad only, so that when you select a row in the list in the Master view it does nothing on iPhone but is working fine on iPad.
So my question is can I create and perform the segue that allows to show the Detail View on the didSelectRowAtIndexPath method ?
Here's what i've done so far :
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let segue = UIStoryboardSegue(identifier: "test", source: self, destination: detailViewController!)
performSegueWithIdentifier("test", sender: self)
}
but when running and selecting a row the app was crashing telling it needed a performhandler so i added this :
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let segue = UIStoryboardSegue(identifier: "test", source: self, destination: detailViewController!, performHandler: { () -> Void in
let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
let controller = self.detailViewController!
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
})
performSegueWithIdentifier("test", sender: self)
}
and now when selecting a row xcode says that there is no segue with such identifier "test".
I also tried to call it by segue.perform() and add the performHandler content into the prepareForSegueMethod :
if segue.identifier == "test" {
if let indexPath = self.tableView.indexPathForSelectedRow {
let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem()
controller.navigationItem.leftItemsSupplementBackButton = true
}
}
and it does just nothing, doesn't crash, just highlight the row i selected and that's all
Can you guys help me ?
EDIT : As Oleg Gordiichuk said, it's not possible to do what I want to do without Storyboards, so thanks for his help :)

Segue it is component of the storyboard interaction it is possible to understand from name of the class UIStoryboardSegue. It is bad idea to create segues programmatically. If i am not making mistake storyboard creates them for you.
For solving of you're issue try to use some common ways like simply present ViewController.
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("id") as! MyController
self.presentViewController(vc, animated: true, completion: nil)
As i understand from our conversation in comments. You would like to create navigation for tableview to details view using segues without storyboard. For now it is impossible to do this without storyboard.
For future learning try to investigate this information.

One way is to use the didSelectRow method for tableView
Swift 3.x
// MARK: - Navigation & Pass Data
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected Row \(indexPath.row)")
let nextVC = YourNextViewController()
nextVC.YourLabel.text = "Passed Text"
nextVC.YourLabel.text = YourArray[indexPath.row]
// Push to next view
navigationController?.pushViewController(nextVC, animated: true)
}

Related

Passing Data Forward In Swift Without Segue

I'm currently making a to do list app using Swift 4. The home view controller has a tableview with some categories in it and when one is selected, it takes the user to a view controller where the items in that category are listed. I have a bug however as only the most recent item is showing in the list.
I think this is due to the way I am navigating to the list view controller. I am currently doing this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let destinationVC = ListVC()
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedCategory = categoryArray[indexPath.row]
}
navigationController?.pushViewController(destinationVC, animated: true)
tableView.deselectRow(at: indexPath, animated: true)
}
And in the list view controller, I just have this to load the data:
var selectedCategory : Category? {
didSet {
loadItems()
}
}
I firstly created this app using storyboards and when using segues, it worked completely fine.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "goToItems", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let destinationVC = segue.destination as! TodoListVC
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedCategory = categoryArray[indexPath.row]
}
}
So basically, the problem is that in the secondary list view controller, it will only show the most recently added item and no other ones even when they are stored in core data. I think it is to do with the way I am showing the secondary view controller as I am creating a new object every time.
How to properly go to the next view controller?
Remove the segue and add the storyboard id
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "storyboard_id") as! TodoListVC
vc.selectedCategory = categoryArray[indexPath.row]
self.navigationController?.pushViewController(vc, animated: true)
}
Try this it will help you:-
You can send data from one view controller to another using storyboard
instance.
let next = self.storyboard?.instantiateViewController(withIdentifier: "NextControllerStoryBoard_id")as! NextController
next.str = "data which you want to pass"
self.navigationController?.pushViewController(next, animated: true)
here NextController is your controller class name where you want to go.str is the string name which you declare on NextController like
let str = String()
you are able to send string in that variable in same way you send any thing array dictionary ,image, Int value etc.
NextControllerStoryBoard_id is id which you declare at storyboard of that controller
In storybard id add your storybard id
Hope this will help you
I think that with this chunk of code I already sensed that you are passing data to the other view controller the incorrect way:
let destinationVC = ListVC()
if let indexPath = tableView.indexPathForSelectedRow {
destinationVC.selectedCategory = categoryArray[indexPath.row]
}
...
What I would suggest is that, instead of passing the data this way, you have to pass an array containing the items within the selected category using an array, then pass that array via the prepare for segue.
Then from the viewdidappear or viewdidload method in the receiving view controller, use the passed array from the source VC and use that as a datasource for your table view within that 2nd VC.

Segue lag, tableview in Swift

I am working at my first application in Swift 3. I am using tableView (by "extension MainController: UITableViewDataSource"). And from this tableView, by storyboard I have two segues. One for editing (by clicking on accessory icon) and the second one for more detail screen (by clicking on a table row). I am not calling this segues by code, but by storyboard.
And my problem is that there is sometimes huge lag. Like after clicking on a row, the next screen is showing after 30 seconds. But now always. Sometimes its working immediately. Interesting thing is that when I touch row 1, and nothing happens, next I am clicking row 2 and then row 1 is appearing.
I am also using delegates, this is the code for preparing segues:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// 1
if segue.identifier == "AddSensor" {
// 2
let navigationController = segue.destination
as! UINavigationController
// 3
let controller = navigationController.topViewController
as! AddController
// 4
controller.delegate = self
}
else if segue.identifier == "EditSensor" {
let navigationController = segue.destination
as! UINavigationController
let controller = navigationController.topViewController
as! AddController
controller.delegate = self
if let indexPath = tableView.indexPath(
for: sender as! UITableViewCell) {
controller.sensorToEdit = sensors[indexPath.row]
}
}
else if segue.identifier == "DetailSeq" {
let navigationController = segue.destination
as! UINavigationController
let controller = navigationController.topViewController
as! DetailController
controller.delegate = self
if let indexPath = tableView.indexPath(
for: sender as! UITableViewCell) {
controller.sensorRecieved = sensors[indexPath.row]
}
}
}
I was reading that it was common bug in iOS8 and could be resolved by adding
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "DetailSeq",sender: self)
}
}
But it didn't worked for me. I don't know what should I do next to resolve this problem. Can anyone guide me?
According to this SO question, you may be able to fix your bug if you present your view controller in code rather than with the segue in the storyboard. Something like this, where your destination is the VC that you want to go to.
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath:
NSIndexPath) {
DispatchQueue.main.async {
self.presentViewController(destination, animated: true) { () -> Void
in
}
}
}
You have to use like this :
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
DispatchQueue.main.async {
self.performSegue(withIdentifier: "DetailSeq",sender: self)
}
}

PageMenu pod presents Modal segue instead of Push segue

This question relates to:
SWIFT: Push segue is resulting in a modal segue instead
'Show' segue in Xcode 6 presents the viewcontroller as a modal in iOS 7
I understand this question might be very similar to others. But I have been unable to use some of the answers to solve my issue.
Here is how my storyboard looks:
The viewController has a segmentControl that controls two viewControllers. I now want to segue to the DetailViewController, but it is appearing as modal segue which hides the tabBar and navigationBar.
I have tried deleting and recreating the segue as the some off the answers have suggested but it doesn't solve anything. Is there anything someone could suggest me or direct me to?
Edit:
After testing out the demo that the pod provides I was able to outline the issue I am struggling with. I have implemented the same methods in which it is practically identical. The only difference is that my method for this PageMenu does not use nib files like the demo has done.
In my tableView delegate I am trying to pass a recipe data to the DetailView. This is how my prepareForSegue and didSelect looks:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "detail", sender: recipe)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detail" {
let vc = segue.destination as! DetailViewController
let indexPath = tableView.indexPathForSelectedRow!
vc.recipe = RecipeManager.shared.recipes[indexPath.row]
}
}
Here is the demo's didSelect:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let newVC : UIViewController = UIViewController()
newVC.view.backgroundColor = UIColor.white
newVC.title = "Favorites"
parentNavigationController!.pushViewController(newVC, animated: true)
}
When comparing it with the demo I am struggling to understand where to implement the parentNavigationController!.pushViewController(newVC, animated: true) which I believe will solve my issue.
Assuming you implemented the parentNavigationController as they did in the demo, you are almost all set.
Delete your existing Segue - you won't be using it.
Give your DetailViewController a Storyboard ID - such as "DetailVC"
Change your code to instantiate the DetailVC and push it onto the parent Nav Controller
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let vc = self.storyboard?.instantiateViewController(withIdentifier: "DetailVC") as? DetailViewController {
vc.recipe = RecipeManager.shared.recipes[indexPath.row]
parentNavigationController!.pushViewController(vc, animated: true)
}
}

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:

Resources