managing page navigation at swift2 - ios

I'm trying to learn page navigation without using "Navigation Controller".
Created a button and function like;
#IBAction func backPressed(sender: AnyObject) {
self.performSegueWithIdentifier("page2ToMain", sender: self)
}
It works fine.
I need to pass data from page 2 to page 3. So, inside "didSelectRowAtIndexPath" I used "performSegueWithIdentifier" and override "prepareForSegue" function as below;
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.selectedRow = self.dataArray[indexPath.row]
self.performSegueWithIdentifier("page2ToPage3", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let nextViewController = segue.destinationViewController as! ViewController3
nextViewController.data = self.selectedRow
print(self.selectedRow)
}
When I click the table cell it works well, jumps to other view controller and I see data variable.
But when I press back button it fails with;
Could not cast value of type 'test3.ViewControllerMain' (0x1045469f0) to 'test3.ViewController3' (0x1045466e0).
How can I solve the problem?

You can test for this with optional binding:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let nextViewController = segue.destinationViewController as? ViewController3 {
nextViewController.data = self.selectedRow
print(self.selectedRow)
}
}
Or look at the segue identifier and then test for that:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "page2ToPage3" {
let nextViewController = segue.destinationViewController as! ViewController3
nextViewController.data = self.selectedRow
print(self.selectedRow)
}
}

Related

Receiver has no segue with identifier 'goToDetail'

I've double-checked that my identifier is spelled correctly in the storyboard and that the segue is pointed in the right direction, but I keep receiving this error. Could someone take a look at my code to see if I'm missing something?
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let selectedData = tableData[indexPath.row]
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "goToDetail", sender: selectedData)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? DetailViewController {
destination.vocab.text = sender as? String
}
}
Edit:
segue can be used only with if you have a UINavigationController that will handle the navigation. You performing a segue to UINavigationController. UINavigationController should be at the root of your storyboard.
In your didSelectRowAt function change
performSegue(withIdentifier: "goToDetail", sender: selectedData)
To NavigationController Identifier (Note if you do not have identifier already set up in storyboard you will need to do that first)
performSegue(withIdentifier: "goToNavigationConrtoller", sender: selectedData)
And then change the prepareForSegue function to below.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
//check destination for segue is Navigation controller
if let navVC = segue.destinationViewController as? UINavigationController {
// get hold of the first viewController.
if let destination = navVC.viewControllers[0] as? DetailViewController {
destination.vocab.text = sender as? String
//all the other code you need
}
}
}

Passing data between segue with Swift 2.0

I seem to be following tutorials to the tee yet I can't get my data to pass to my second view controller without being nil.
I am new to Swift so I'm probably also not using optionals correctly. Here is how I have my code set up.
import UIKit
class DetailsViewController: UIViewController {
var book : PLBook?
override func viewDidLoad() {
super.viewDidLoad()
//View Did Load
print(self.book)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
}
}
Then this is how I am presenting the second view controller and preparing for segue.
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("toDetailVC", sender:self)
}
//MARK: Navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "toDetailVC"){
//prepare for segue to the details view controller
if let detailsVC = sender?.destinationViewController as? DetailsViewController {
let indexPath = self.tableView.indexPathForSelectedRow
detailsVC.book = self.books[indexPath!.row]
}
}
}
In the second view controller, the book var is always nil. Any ideas how I can get the data to pass?
Try This:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "toDetailVC") {
//prepare for segue to the details view controller
let detailsVC = segue.destinationViewController as! DetailsViewController
let indexPath = self.tableView.indexPathForSelectedRow
detailsVC.book = self.books[indexPath!.row]
}
You should be using segue.destinationViewController, not sender?.destinationViewController.

Getting object for tapped UITableViewCell in new UIView?

What is the right way to segue from a cell in a UITableViewCell to a new view, passing parameter data?
I have specified a segue from my prototype cell in my UITableViewCell, that links it to a new UIVIew and has it set to show (aka push). The new UIView displays, but I am not sure how to make tell the UIView the section/row that was selected or tell it about the object associated with that selection.
An abridged version of my code is shown below:
class MyTableViewController : UITableViewController {
// other code omitted
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let files = filesByDate[filesByDateKeys![indexPath.section]]
self.selectedFile = files![indexPath.row]
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SegueToFileDetails") {
let destinationViewController = segue.destinationViewController as! FileDetailsViewController
destinationViewController.file = self.selectedFile
}
}
}
class FileDetailsViewController : UIViewController {
var file: NSURL
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
print("File: ", file)
}
}
What I find happening is the tableView() function is called after the prepareForSegue() functon, causing the file attribute to be nil when viewWillAppear() is called.
A little more search turned up this other post, which indicated the right approach. The tableView() function in my question is not needed. Instead (in Swift 2):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "SegueToFileDetails") {
let destinationViewController = segue.destinationViewController as! FileDetailsViewController
let path = self.tableView.indexPathForSelectedRow
let files = filesByDate[filesByDateKeys![path!.section]]
destinationViewController.file = files![path!.row]
}
}
And if you want to simply do behaviour based on the specific destination class, based on another suggestion:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let destinationViewController = segue.destinationViewController as? FileDetailsViewController {
let path = self.tableView.indexPathForSelectedRow
let files = filesByDate[filesByDateKeys![path!.section]]
destinationViewController.file = files![path!.row]
}
}

Passing data with segue through navigationController

I'm trying to push data from one viewController to another. I've connected a viewController to another ViewController's navigationController and then set the identifier to "showItemSegue". I get an error in these two lines:
var detailController = segue.destinationViewController as ShowItemViewController
detailController.currentId = nextId!
Image illustration:
The code:
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
nextId = itemArray?.objectAtIndex(indexPath.row).objectForKey("objectId") as? NSString
self.performSegueWithIdentifier("showItemSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "showItemSegue") {
var detailController = segue.destinationViewController as ShowItemViewController
detailController.currentId = nextId!
}
}
The destination view controller of the segue is the UINavigationController. You need to ask it for its top view controller to get to the real destination view controller:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showItemSegue" {
let navController = segue.destination as! UINavigationController
let detailController = navController.topViewController as! ShowItemViewController
detailController.currentId = nextId!
}
}

Prepare for Segue in Swift

I'm facing the error message:
"UIStoryboardSegue does not have a member named 'identifier'"
Here's the code causing the error
if (segue.identifier == "Load View") {
// pass data to next view
}
On Obj-C it's fine using like this:
if ([segue.identifier isEqualToString:#"Load View"]) {
// pass data to next view
}
What am I doing wrong?
This seems to be due to a problem in the UITableViewController subclass template. It comes with a version of the prepareForSegue method that would require you to unwrap the segue.
Replace your current prepareForSegue function with:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "Load View") {
// pass data to next view
}
}
This version implicitly unwraps the parameters, so you should be fine.
Swift 4, Swift 3
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "MySegueId" {
if let nextViewController = segue.destination as? NextViewController {
nextViewController.valueOfxyz = "XYZ" //Or pass any values
nextViewController.valueOf123 = 123
}
}
}
I think the problem is you have to use the ! to unbundle identifier
I have
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
if segue!.identifier == "Details" {
let viewController:ViewController = segue!.destinationViewController as ViewController
let indexPath = self.tableView.indexPathForSelectedRow()
viewController.pinCode = self.exams[indexPath.row]
}
}
My understanding is that without the ! you just get a true or false value
For Swift 2.3,swift3,and swift4:
Create a perform Segue at didSelectRowAtindexPath
For Ex:
self.performSegue(withIdentifier: "uiView", sender: self)
After that Create a prepareforSegue function to catch the Destination segue and pass the value:
Ex:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "uiView"{
let destView = segue.destination as! WebViewController
let indexpath = self.newsTableView.indexPathForSelectedRow
let indexurl = tableDatalist[(indexpath?.row)!].link
destView.UrlRec = indexurl
//let url =
}
}
You need to create a variable named UrlRec in Destination ViewController
Swift 1.2
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "ShowDeal") {
if let viewController: DealLandingViewController = segue.destinationViewController as? DealLandingViewController {
viewController.dealEntry = deal
}
}
}
Prepare for Segue in Swift 4.2 and Swift 5.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "OrderVC") {
// pass data to next view
let viewController = segue.destination as? MyOrderDetailsVC
viewController!.OrderData = self.MyorderArray[selectedIndex]
}
}
How to Call segue On specific Event(Like Button Click etc):
performSegue(withIdentifier: "OrderVC", sender: self)
this is one of the ways you can use this function, it is when you want access a variable of another class and change the output based on that variable.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let something = segue.destination as! someViewController
something.aVariable = anotherVariable
}
Provided you aren't using the same destination view controller with different identifiers, the code can be more concise than the other solutions (and avoids the as! in some of the other answers):
override func prepare(for segue: NSStoryboardSegue, sender: Any?) {
if let myViewController = segue.destinationController as? MyViewController {
// Set up the VC
}
}
Change the segue identifier in the right panel in the section with an id. icon to match the string you used in your conditional.
override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
if(segue!.identifier){
var name = segue!.identifier;
if (name.compare("Load View") == 0){
}
}
}
You can't compare the the identifier with == you have to use the compare() method

Resources