I need to pass a string with prepareForSegue from a tableView disclosure link. Here is the prepareForSegue code I use. This is the code I found in several cases when other users needed to do the same thing, but in my case it doesn't work. Problem is with indexPathForSelectedRow() that is nil:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "alertsDetail" {
let detailAlertViewController = segue.destinationViewController as DetailAlertViewController
println(alertTable.indexPathForSelectedRow()) // NIL
if let indexPath = alertTable.indexPathForSelectedRow() {
let entryToPass = unpublishedPhotosObjectId[indexPath.row]
detailAlertViewController.entryId = entryToPass
}
}
}
I named the tableView "alertTable" and not self because the tableview is not a view controller, just a view.
In case needed, here is tableview code:
#IBOutlet weak var alertTable: UITableView!
/////////////TableView - START
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return unpublishedPhotos.count
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 170
}
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
tableView.separatorColor = UIColor.clearColor()
let cell = tableView.dequeueReusableCellWithIdentifier("adminAlertsCell") as? adminAlertsCell
var data = unpublishedPhotos[indexPath.row].getData()
let image = UIImage(data: data)
cell!.myImageInCell.image = image
return cell
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
// Add access to cell
let cell = tableView.cellForRowAtIndexPath(indexPath) as? adminAlertsCell
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
println(cell!.banSwitch.on)
}
}
/////////////TableView - END
You should make the segue from the controller instead of directly from the detail disclosure button. Implement the method,
tableView:accessoryButtonTappedForRowWithIndexPath: and call performSegueWithIdentifier:sender: from inside that method. Pass the in-depth as the sender argument so you have access to that in prepareForSegue,
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
let indexPath = sender as NSIndexPath
if segue.identifier == "alertsDetail" {
let detailAlertViewController = segue.destinationViewController as DetailAlertViewController
let entryToPass = unpublishedPhotosObjectId[indexPath.row]
detailAlertViewController.entryId = entryToPass
}
}
Your issue is stated in the comments to your question, and there are several solutions. Perhaps the quickest since you only have one section, is to assign the indexPath.row to the tag of the cell. Then in your prepare for segue, the sender will be your cell. You can get the value out of it. So in your cellForRow method before your return your cell:
cell!.tag = indexPath.row
Then in your prepareForSegue:
let cell = sender as? adminAlertsCell
println(cell!.tag)
Here I am just printing it, but you can use it to pass the row.
Related
How to make Each Cell open the specific view for its indexpath.
In tableview didselect what should i do to make each cell open as its own indexpath so each cell have a different data in the next view
i am tryin when click in a cell in the tableview the next view present it self with it's own data as the next view contain a uitextview like in note app
what should i apply at row didselect
// MARK: -TableFunctions
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return SavingTasks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let newtask = self.SavingTasks[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.TheLabel?.text = newtask
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if(editingStyle == .delete)
{
self.SavingTasks.remove(at: indexPath.row)
self.TasksTable.deleteRows(at: [indexPath], with: .fade)
GetData()
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let NewIndex = self.SavingTasks[indexPath.row]
let view = self.storyboard?.instantiateViewController(withIdentifier: "TaskDetail") as! TaskDetail
view.SavingDetails = [NewIndex]
view.Index = indexPath.row
self.navigationController?.pushViewController(view, animated: true)
}
next class should be appeared
class TaskDetail: UIViewController {
var Delegate: NoteDetailDelegate!
var SavingDetails = [String]()
var Index: Int?
#IBOutlet weak var TaskDetailsFiled: UITextView!
#IBAction func SaveTDF(_ sender: UIButton) {
UserDefaults.standard.set(TaskDetailsFiled.text, forKey: "Saved")
self.navigationController?.popViewController(animated: true)
}
You can use a segue and prepare(for:sender:) to get the next view controller ready more easily than instantiating the view controller and popping it via code. Official documentation here and a sample app from Apple here
An implementation example:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "mysegue"{
if let nextViewController = segue.destination as? NextViewController{
nextViewController.Index = 2
}
}
}
A highlight from the official doc:
For example, if the segue originated from a table view, the sender parameter would identify the table view cell that the user tapped
If you want to stick with the code implementation, you can call view.myvariable = myvalue in your didSelect
I am trying to pass cell's tag data to another viewcontroller's variable
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell!
print(currentCell.tag)
valueToPass = currentCell.tag
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let Dest = segue.destinationViewController as! EventDetail
if (segue.identifier == "eDetay") {
Dest.eventid = String(valueToPass)
}
}
When i try as it is, valueToPass is always passed the previous data.
Is there a way to get selected cell data from prepareForSegue ?
What is the best way to do that?
You are overriding the indexPath parameter that is being passed to you.
Remove the first let statement. Use the indexPath that is being passed to you.
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!)
{
let cell = tableView.cellForRowAtIndexPath(indexPath) as YourCell
//cell.value, cell.text, cell.randomValue or whatever you need
}
Like Title
More information - I am populating my view controller with
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "showCalendars" {
// Setup new view controller
print("happening")
let vc = segue.destinationViewController as! CalendarSelectionViewController
for item in self.approvedCalendars {
vc.sentCalendars.append(item)
}
vc.tableView.reloadData()
vc.calendarDelegate = self
}
}
and my view controller code looks like :
import UIKit
import EventKit
class CalendarSelectionViewController: UITableViewController {
var sentCalendars: [EKCalendar]! = []
var calendarDelegate: selectCalendarDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.title = "My Calendars"
//tableView.tableFooterView = UIView()
tableView.reloadData()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.sentCalendars.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("calendarCell", forIndexPath: indexPath)
cell.textLabel?.text = sentCalendars[indexPath.row].title
return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 60
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
}
}
whenever i click on any uitableview cell, my application crashes and I receive "fatal error: Array index out of range".
I've tried printing out the indexPath.row in the didSelectRowAtIndexPath method and it prints the correct index, so why is this crashing? Is there a memory leak somewhere and the tableview is not showing the proper information? Thanks for your help.
Investigated my storyboard, I had an unwind segue that wasn't being used and was causing a fatal error: array index out of bounds. Thanks for the help!
I have an array in my ViewOne, which I pass to ViewTwo with the prepareForSegue function.
When I delete data of my array in ViewTwo and go back with the back button on the NavigationController or by swiping to right, the array in ViewOne has still all the data and don't know that I deleted something of it.
Is there any solution for this problem?
ViewOne:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "submitSegue") {
let shoppingCart = segue.destinationViewController as! ShoppinCartScreen;
if(artikel != nil) {
shoppingCart.alleArtikel = alleArtikel
print("Test: \(artikel?.artikelnummer)")
}
}
}
ViewTwo:
var alleArtikel = [Artikel]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return alleArtikel.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("ShoppingCartScreenCell", forIndexPath: indexPath) as!ShoppingCartScreenCell
let eintrag = alleArtikel[indexPath.row]
cell.previewImage.image = eintrag.foto
cell.artikelNummer.text = eintrag.artikelnummer
return cell
}
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if(editingStyle == .Delete) {
alleArtikel.removeAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
}
}
I have a main View (ViewOne) and a TableView(ViewTwo).
In Swift, arrays are value types not reference types (see Apple Developer Blog entry), so when you 'pass' it to view2 you are really just making a copy. View2 modifies the copy but the original remains unchanged.
Instead of using a prepareForSegue method when going back, which to my knowledge is not possible, just run the viewWillDisappear function. Basically this is the viewDidLoad function for when the view disappears. It will run when you are performing a segue when you are leaving the view.
example:
override func viewWillDisappear(animated: Bool)
{
super.viewWillDisappear(animated)
print("the view is hidden")
}
I'm working in a UITableView which contains 5 rows ("a" to "e"), and when I click on one of the rows, it shows me in the next UITableView the letter I chose as a Header (with the prepareForSegue function). Actually, until this point it works perfectly.. BUT when I try to add more "headers" in the 2nd tableView after clicking in more than one row from the first UITableView, it just show me the last option (for example, if I click first in "a", then "d" and then "c"... the second UITableView just show me the row "c" as a header, not the other 2 rows).
How can I choose multiple rows and send those options to a second UITableView through a prepareForSegue function?
My line of codes for the first view are these:
let array = ["a", "b", "c", "d", "e"]
#IBOutlet var initialTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segueA" {
if let destination = segue.destinationViewController as? Content {
if let selectedRow = initialTableView.indexPathForSelectedRow?.row {
destination.title = array[selectedRow]
}
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.array.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cellA", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = array[indexPath.row]
return cell
}
The second view contains these lines:
var contentArray:[String] = []
#IBOutlet var contentTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
contentArray.append(title!)
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return contentArray.count
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellContent = tableView.dequeueReusableCellWithIdentifier("cellContent", forIndexPath: indexPath) as UITableViewCell
cellContent.textLabel!.text = "Second test"
return cellContent
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return contentArray[section]
}
Thanks!
Joe.
For solving of you're issue.You should enabled multiple selection by :
tableView.allowsMultipleSelection = YES;
Than you should remember items you selected in first viewContoller. For convenience try to use:
var indexPathsForSelectedRows: [NSIndexPath]? { get }
And than send this information to the another viewController by segue.
Example:
let array = ["a", "b", "c", "d", "e"]
#IBOutlet var initialTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
initialTableView.allowsMultipleSelection = YES
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "segueA" {
if let destination = segue.destinationViewController as? Content {
if let selectedRows = initialTableView.indexPathsForSelectedRows {
//hear you have option to send items that are selected to another controller or send only indexPath.
}
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.array.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cellA", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = array[indexPath.row]
return cell
}
You have to store the selected rows yourself in a list or array
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//check if self._selectedIndices (your array) contains indexPath.row
//if yes then remove it from array
cell.accessoryType = UITableViewCellAccessoryType.None // remove check mark if you want to use it
//if no then add it to array
cell.accessoryType = UITableViewCellAccessoryType.Checkmark // add check mark if you want to use it
}
then in your prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// use self._selectedIndices to get the selected row indices
// self._dataSource[index] for the actual data
}
Just enable multiple selection on the tableview, and use the indexPathsForSelectedRows variant to get the full list. You can then either pass the whole list from your data source + the indexes, or map the indexes to the actual values.