UITableView with sections prepareForSegue - ios

I am working on a UITableView with multiple sections. Each section has a multiple of items driven from different arrays. When I click the cell from any section I want the name of the item to pass to an another view controller. I know how to use the prepareForSegue function with one array, but I need your help with more than one array.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let secondScene=segue.destinationViewController as! nextPageViewController
if let indexPath=self.tableView.indexPathForSelectedRow{
let array1=TableData[indexPath.row]
secondScene.currentPhoto=array1
}

Assuming your model is laid down like this:
let section1Array = ["row1", "row2"]
let section2Array = ["row1", "row2"]
let section3Array = ["row1", "row2"]
let sectionArray = [section1Array, section2Array, section3Array]
Here, sectionArray derives your sections and section1Array, section2Array & section3Array derives your individual section rows.
Having said that, this is how you would retrieve and send this data to your second scene:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let secondScene = segue.destinationViewController as! nextPageViewController
if let indexPath = self.tableView.indexPathForSelectedRow {
let currentPhoto = sectionArray[indexPath.section][indexPath.row]
secondScene.currentPhoto = currentPhoto
}
}

If your table has multiple sections, then in prepareForSegue use indexPath.section to find out which section was clicked on, which tells you which of your backing arrays to use. Then select the item from the array using indexPath.row and pass that to destinationViewController as the photo.

Related

Passing value from Firebase from one tableView to another

I am trying to pass value I get from Firebase to another tableView. I get 2 values from Firebase - "Brands" and "Products". I am trying to make like car app. If you click on Ford then new tableView will appear and shows all the Ford models. This is what I've done so far.
like this I get Brands from Firebase:
func parseSnusBrands(){
let ref = FIRDatabase.database().reference().child("Snuses").child("Brands")
ref.observeSingleEventOfType(.Value, withBlock: { (snapshot) in
if snapshot.exists() {
if let all = (snapshot.value?.allKeys)! as? [String]{
for a in all{
if let products = snapshot.value![a] as? [[String:String]]{
self.snusBrandsArray.append(["key":a,"value":products])
}
}
self.snusBrandsTableView.reloadData()
}
}
})
}
And like this I detect which cell is clicked and print the product that belongs to the clicked Brand:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
print("products at \(indexPath.row) --> \(snusBrandsArray[indexPath.row]["value"])")
}
How to pass the (snusBrandsArray[indexPath.row]["value"]) to new tableView? I tried using segues and looking for tutorials like "How to pas value between viewControllers" but I am out of luck. Right now I have 2 tableViewController.swift files and one tableViewCustomCell.swift file. Do I need some more files?
For send data, first of all declare your variable in 2nd view controller..
var productsValue = [[String:String]]()
and in 1st viewcontroller
var valueTopass = [[String:String]]()
Than in didSelectRowAtIndexPath, take a value in one valueTopass
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("products at \(indexPath.row) --> \(snusBrandsArray[indexPath.row]["value"])")
if let products = snusBrandsArray[indexPath.row]["value"] as? [[String:String]]{
valueTopass = products
performSegueWithIdentifier("toProducts", sender: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if (segue.identifier == "toProducts") {
var viewController = segue.destinationViewController as! SnusProductsTableViewController
viewController.productsValue = valueTopass
print(productValues)
}
}
You need to use Segues to pass the data forward.
To pass data from the current view controller to the next new view controller using segues, first create a segue with an identifier in the relevant storyboard. Override your current view controller's prepareForSegue method. Inside the method check for the segue you just created by its identifier. Cast the destination view controller and pass data to it by setting properties on the downcast view controller.
Setting an identifier for a segue:
Segues can be performed programatically or using button action event set in the storyboard by ctrl+drag to destination view controller.
You can call for a segue programatically, when needed, using segue identifier in the view controller:
func showDetail() {
performSegueWithIdentifier("showDetailingSegue", sender: self)
}
You can configure segue payload in the override version of prepareForSegue method. You can set required properties before destination view controller is loaded.
Swift
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showDetailingSegue" {
let controller = segue.destinationViewController as! DetailViewController
controller.isDetailingEnabled = true
}
}
DetailViewController is the name of the second view controller and isDetailingEnabled is a public variable in that view controller.
To expand on this pattern, you can treat a public method on DetailViewController as a pseudo initializer, to help initialize any required variables. This will self document variables that need to be set on DetailViewController without having to read through it's source code. It's also a handy place to put defaults.
Swift
func initVC(isDetailingEnabled: Bool) {
self.isDetailingEnabled = isDetailingEnabled
}
Why not pass the whole dictionary with all the contents from firebase to the new VC using prepare for segue?
And then store the dict in the destinationVC data model?
That should do the trick.

Passing Core Data objects to another view controller when selecting row from UITableView

EDIT based on provided answer:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedName = quizNames[indexPath.row]
performSegueWithIdentifier("saveSegue", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "saveSegue" {
let inputController = segue.destinationViewController as? QAInputViewController
inputController?.quizName = selectedName
}
}
I have done some research on here trying to figure out exactly how to use prepareForSegue in order to pass the selected Core Data object from a UITableView cell to a second View Controller, but what i found and tried to implement did not work out for me as it seems some of the code might be outdated. Here is what i am trying to do:
I populate a UITableView with an array of names of type Name which is my NSManagedObject. When i select a specific name it will segue me to an input screen where a question and answer will be submitted. I want to make sure that the question and answer that are submitted stay assigned to the previously selected name. I am not sure how to set this up in prepareForSegue. I did set up my data model with relationships, so if i did that correctly it should work once i understand how to implement it. Is there some way i can check the currently selected name so that i know any question and answer that is inputted will be saved to that name?
Relative to my above question, i want the title of the second View Controller to show the name of the previously selected name.
Basically i am just looking for the guidance on to get this implemented in Swift 2. Thank you very much for your help.
EDIT: Passing Core Data objects from UITableViewCell to another View Controller
The above link is the solution i tried implementing that was not working for me. Specifically:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showTaskDetail" {
let detailVC: TaskDetailViewController = segue.destinationViewController as! TaskDetailViewController
let indexPath = self.tableView.indexPathForSelectedRow()
let thisTask = fetchedResultsController.objectAtIndexPath(indexPath!) as! TaskModel
detailVC.detailTaskModel = thisTask
detailVC.delegate = self
}
This is how I do it:
At the top of my class I'll have a var that stores the selected item:
var selectedTask: Task?
Then in my tableViews didSelectRow method:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
selectedTask = tasks[indexPath.row]
performSegueWithIdentifier("showTaskDetail", sender: self)
}
And finally:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showTaskDetail" {
let detailVC: TaskDetailViewController = segue.destinationViewController as! TaskDetailViewController
detailVC.detailTaskModel = selectedTask
detailVC.delegate = self
}
}
However, I'd be more inclined to just pass some kind of ID/name and perform another fetch with a new moc rather than pass around core data objects.
You'll get less threading issues this way and it will make things far easier should you need to deep link into your app, from say, a notification or something.
Mocs are cheap, use them once, and throw them away.

Send variable value to next view controller when click a table cell

I have two table view controllers
InvoiceList view controller
InvoiceShow view controller
I use didSelectRowAtIndexPath method as bellow to get selected table cell specific value
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let rowObject = objects[indexPath.row]
let invoicehash = rowObject["hash_key"]!
}
i need to send invoicehash value to InvoiceShow controller when click the table cell of InvoiceList
i tried to use prepareForSegue function. but it is not applicable because it will trigger before the didSelectRawAtIndexPath function. so when i implemented it, gives the previous click event variable value. not correct one.
Please help me to access invoiceHash variable value from InvoiceShow controller
You will get the selected cell in prepareForSegue method itself.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let selectedIndexPath = self.tableView.indexPathForSelectedRow()!
let rowObject = objects[selectedIndexPath.row]
let invoiceHash = rowObject["hash_key"]!
let invoiceShowViewController = segue.destinationViewController as! InvoiceShowViewController
// Set invoiceHash to `InvoiceShowViewController ` here
invoiceShowViewController.invoiceHash = invoiceHash
}
You can still use a segue if you want and/or already setup on your storyboard.
You just need to connect the two view controllers in Interface Builder directly from one to another.
So, start ctrl-dragging from the controller itself and not from the TableViewCell (take a look at the screenshot)
then use the performSegueMethod with the new segue identifier like this:
self.performSegueWithIdentifier("mySegueIdentifier", sender: self)
and finally, your prepareForSegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "mySegueIdentifier" {
let selectedIndex = self.invoiceTableView.indexPathForSelectedRow
//if element exist
if selectedIndex?.row < myDataSourceArray.count {
let destination = segue.destinationViewController as! InvoiceShowViewController
let invoice = myDataSourceArray[selectedIndex!.row]
destination.invoice = invoice
}
}
}
That's it!

how can I move to another view controller?

I have a problem with indexPathForSelectedRow()
I have 2 viewcontroller:
tableview and view controller
I want to move from tableview to another controller
and I used func prepareForSegue but I have problem in indexpathselectedrow()
This is issue for the problem:
cannot invoke "indexpathforselectedRow" with no arguments
The Xcode is a last version
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "show"
{
let indexpath = tableView.indexPathForSelectedRow()
let detailvc: fiveViewController = segue.destinationViewController as! fiveViewController
}
}
There is the indexPathForSelectedRow definition in Swift 1.2:
- (NSIndexPath *)indexPathForSelectedRow; // returns nil or index path representing section and row of selection.
There is its definition in Swift 2.0:
var indexPathForSelectedRow: NSIndexPath? { get } // returns nil or index path representing section and row of selection.
In Swift 2.0, the indexPathForSelectedRow is a property not a method, so you should change:
let indexpath = tableView.indexPathForSelectedRow()
to
let indexpath = tableView.indexPathForSelectedRow
Sounds like there is no reference to tableView or it's not of type UITableView.
override func prepareForSegue(segue: UIStoryboardSegue , sender: AnyObject?) {
if segue.identifier == "show"
{
let indexpath = self.tableView.indexPathsForSelectedRows()!
let detailv:fiveViewController = segue.destinationViewController as! fiveViewController
detailv.pic = self.menu[indexpath.row].picName
}
this link for the pic " my problem "

How to access segue in 'didSelectRowAtIndexPath'?

I know how to pass data using segues from prepareForSegue function, but the thing i have a TableViewCell from which there are two possible segues to two different ViewControllers (let's just say A, B as of now).
It was suggested here that it is best to connect the segues to View controller rather than the tableCell itself, which infact worked perfectly. But i want to pass information to the second View controller when the cell is clicked, So how to access segue that i connected to the Source ViewController.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showQuestionnaire"{
if let indexPath = self.tableView.indexPathForSelectedRow() {
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! QuestionnaireController
let patientQuestionnaire = patientQuestionnaires[indexPath.row] as! PatientQuestionnaire
controller.selectedQuestionnaire = patientQuestionnaire
self.performSegueWithIdentifier("showQuestionnaire", sender: self)
}
}
}
Again: This question is not regarding passing information through prepareForSegue
You should be using the didSelectRowAtIndexPath method to determine whether or not a cell was selected, and send the indexPath as the sender of the segue:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("showQuestionnaire", sender: indexPath);
}
Then in your prepareForSegue method, get the indexPath from the sender parameter and use that to pass the correct row/data:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "showQuestionnaire") {
let controller = (segue.destinationViewController as! UINavigationController).topViewController as! QuestionnaireController
let row = (sender as! NSIndexPath).row; //we know that sender is an NSIndexPath here.
let patientQuestionnaire = patientQuestionnaires[row] as! PatientQuestionnaire
controller.selectedQuestionnaire = patientQuestionnaire
}
}
To explain...
I used the index path as the sender so I can easily pass the index path. You could also check for the currently selected cell using other UITableView methods, but I've always done it this way with success
You can't put performSegueWithIdentifier within the prepare for segue method, because performSegueWithIdentifier leads to prepareForSegue; You are just looping around and around with no aim. (When you want to perform a segue, prepareForSegue is always executed)
prepareForSegue doesn't run by itself when a row is selected. This is where you need didSelectRowAtIndexPath. You need a performSegueWithIdentifier outside of the method as described previously, which should be in didSelectRowAtIndexPath

Resources