swift passing data from a tableview cell to view controller - swift

I'm trying to pass some data to a separate view controller, the view controller is connected to a navigation controller, i can get to this view controller using
parentNavigationController!.performSegueWithIdentifier("ExercisePage", sender: self)
but the data isn't passed along, here is my code?
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell2 = tableView.cellForRowAtIndexPath(indexPath) as! SelectionProperties
let desVc = uploadDetails1()
desVc.workoutName = cell2.nameLabel!
desVc.parentNavigationController!.performSegueWithIdentifier("ExercisePage", sender: self)
}
It says it found nil while unwrapping an optional.
desVc.performSegueWithIdentifier("ExercisePage", sender: self) }
if i do this,it says theres no segue

Try this: (You don't have to use all if statements...)
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("ExercisePage", sender: indexPath)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
// Get the new view controller using segue.destinationViewController.
if segue.identifier == "ExercisePage"
{
guard let indexPath = sender as? NSIndexPath else {
return } 
guard let destinationViewController = segue.destinationViewController as? uploadDetails1 else {
return } 
guard let cell = tableView.cellForRowAtIndexPath(indexPath) else {
return } 
guard let _ = cell.nameLabel else { 
return } 
destinationViewController.workoutName = cell.nameLabel!
}
}

Related

Error within tableView when swapping detailView for a different view

I have the function
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let indexPath = tableView.indexPathForSelectedRow {
let object = dailyAgenda[indexPath.row]
if object == "Time Management" {
self.performSegue(withIdentifier: "showTimeManagement", sender: self)
}
else {
self.performSegue(withIdentifier: "showDetail", sender: self)
}}}
And the prepare for segue function
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail" {
if let indexPath = tableView.indexPathForSelectedRow {
let object = dailyAgenda[indexPath.row]
var controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
controller.detailItem = object
controller.textDescription = indepthDescript[indexPath.row]
}}
if segue.identifier == "showTimeManagement" {
var controller = (segue.destination as! UINavigationController).topViewController as! TimeManagement
}
}
But I keep getting the error "Thread 1: Fatal error: Index out of range" when selecting the cell that performs the showTimeManagement segue. The error occurs on the "controller.textDescription = indepthDescript[indexPath.row]]" line within the showDetail segue. Why would it even be running this line in the first place and where am I going wrong?

Second segue from TableViewController creating SIGABRT error relating to the first

I have created a NoteBook application within a larger app. I have all the functionality working including a segue to an Add Note page which triggers programatically from clicking a note (to edit it) or a + barButtonItem.
I need a second segue to send the user back to the home page of the app, but every way I seem to try it conflicts with the existing segue I have in place.
Can anyone suggest a way to get the second segue to work. They both have different identifiers which I am referencing in the methods. Its just the goHome segue that will not work...
class NoteBookViewController: UITableViewController, NoteViewDelegate {
func didUpdateNoteWithTitle(newTitle: String, andBody newBody: String) {
self.noteBookEntries[self.selectedIndex] ["title"] = newTitle
self.noteBookEntries[self.selectedIndex] ["body"] = newBody
self.tableView.reloadData()
saveNotesArray()
}
var noteBookEntries = [[String:String]] ()
#IBAction func newNote() {
var newNote = ["title" : "", "body" : ""]
noteBookEntries.insert(newNote, at: 0)
self.selectedIndex = 0
self.tableView.reloadData()
saveNotesArray()
performSegue(withIdentifier: "editNoteBookSegue", sender: nil)
}
var selectedIndex = -1
func saveNotesArray() {
UserDefaults.standard.set(noteBookEntries, forKey: "notes")
UserDefaults.standard.synchronize()
}
override func viewDidLoad() {
super.viewDidLoad()
if let newNote = UserDefaults.standard.array(forKey: "notes") as? [[String:String]] {
noteBookEntries = newNote
}
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.reply, target: self, action: #selector(NoteBookViewController.navigateToNextViewController))
}
func navigateToNextViewController(){
self.performSegue(withIdentifier: "goHome", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return noteBookEntries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell (withIdentifier: "CELL")! as UITableViewCell
cell.textLabel?.text = noteBookEntries[indexPath.row]["title"]
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
noteBookEntries.remove(at: indexPath.row)
UserDefaults.standard.set(noteBookEntries, forKey: "notes")
self.tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedIndex = indexPath.row
performSegue(withIdentifier: "editNoteBookSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
notesEditorVC.navigationItem.title = noteBookEntries[self.selectedIndex] ["title"]
notesEditorVC.noteBodyText = noteBookEntries[self.selectedIndex] ["body"]
notesEditorVC.delegate = self
}
}
error message relating to original segue - this segue works until the second is added
In your prepareForSegue method first line is:
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
This method is called for each of your segues. When it is called for your first segue it works totally fine because the destination view controller is, in fact, of type NewNoteBookEntryViewController.
However, when this method is called for your second segue, the destination controller is of different type. So, you get a crash when you force downcast it.
You should add some logic to your prepareForSegue method so that you distinguish between segues. For example:
if segue.identifier == "addNote" {
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
//some other code
}
Solved by adding the logic and then adding this to the destination controller:
override func viewWillAppear(animated: Bool) {
self.navigationController?.setNavigationBarHidden(true, animated: true)
}

Prepare for segue delay. Information is lagging but being presented

I'm pushing otherUserUid and otherUserFullName to another view controller but it isn't being call immediately. The information is lagging behind and it takes 2 clicks for the information to appear.
I think preparForSegue: is being called before didSelectRowAtIndexPath: Any solutions how to fix this?
Cheers!
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.performSegueWithIdentifier("jsqDirectory", sender: self)
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
self.otherUserFullName = (currentCell.textLabel?.text)!
print(self.otherUserFullName)
self.otherUserUid = (currentCell.detailTextLabel?.text)!
print(self.otherUserUid)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "jsqDirectory" {
if let viewController = segue.destinationViewController as? JSQViewController{
viewController.senderDisplayName = self.fullName
viewController.senderId = self.firebase.authData.uid
viewController.otherUid = self.otherUserUid
viewController.otherUser = self.otherUserFullName
}
}
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("directoryCell") as UITableViewCell!
let directoryItem = items[indexPath.row]
cell.textLabel?.text = directoryItem.fullName
cell.detailTextLabel!.text = directoryItem.key
cell.detailTextLabel!.hidden = true
return cell
}
in didSelectRowAtIndexPath you have to perform segue at the end of Function like thiss..
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
self.otherUserFullName = (currentCell.textLabel?.text)!
print(self.otherUserFullName)
self.otherUserUid = (currentCell.detailTextLabel?.text)!
print(self.otherUserUid)
self.performSegueWithIdentifier("jsqDirectory", sender: self)

custom cell segue using button swift

I have created custom cell with button inside. Now I am trying to pass a data via pressing on this button, but cant catch indexPath, need your help.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier=="editData"){
if let indexPath = tableView.indexPathForSelectedRow {
let destinationController = (segue.destinationViewController as! AddDetail)
destinationController.info = data[indexPath.row]
let nItem : Dealers = data [indexPath.row]
destinationController.nItem = nItem
also Im trying do the same but from swiping menu:
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]?{
let edit = UITableViewRowAction(style: .Normal, title: "Edit") { (action, indexPath) in
self.performSegueWithIdentifier("addDealer", sender: self)
let name = self.data [indexPath.row].dealerName
print(name)
}
edit.backgroundColor = UIColor.lightGrayColor()
return [delete, edit]
is it possible pass segue from swiping menu?
You can pass indexPath as the sender in performSegueWithIdentifier.
self.performSegueWithIdentifier("addDealer", sender: indexPath)
then
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let indexPath = sender as? NSIndexPath {
// then here you know what the indexPath was
// and can do whatever you want with it
}
...
Try using tableView.indexPathForCell(selectedCell) instead of tableView.indexPathForSelectedRow; you first extract selectedCell as your custom table view cell (YourCustomTableViewCell below):
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
if segue.identifier == "editData" {
let destinationController = segue.destinationViewController as! AddDetail
if let selectedCell = sender as? YourCustomTableViewCell {
let indexPath = tableView.indexPathForCell(selectedCell)!
destinationController.info = data[indexPath.row]
let nItem : Dealers = data[indexPath.row]
destinationController.nItem = nItem
}
}
}
As for the swiping question: I'll get back answer to this.

Segue not sending correct cell info in Swift

I have a tableView that triggers a segue to a detail view when a cell is pressed. The table contains a list of users that the currentUser is friends with. Pressing the cell loads the view for that user (name, profile, etc). It's a very simple app I'm creating to learn how to program.
The problem is that when I press on a cell, it's always loading the user info for the last user in the table (and also happens to be the most recent "friend" that the user made). I have a feeling that the issue is with an if statement I have in the tableView function:
extension MatchesViewController: UITableViewDataSource
{
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return numberOfMatches
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier("MatchCell", forIndexPath: indexPath)
if PFUser.currentUser()!.objectId == self.user1.objectId{
let user = matchesResults[indexPath.row]["user2"] as! PFUser
cell.textLabel?.text = user["first_name"] as! String
self.viewUser = user
}
if PFUser.currentUser()!.objectId == self.user2.objectId{
let user = matchesResults[indexPath.row]["user1"] as! PFUser
cell.textLabel?.text = user["first_name"] as! String
self.viewUser = user
}
return cell
}
}
Here's the segue code, but I don't think there is an issue with it (although I could be wrong):
extension MatchesViewController: UITableViewDelegate
{
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
self.performSegueWithIdentifier("UserSegue", sender: "viewUser")
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "UserSegue") {
let destinationVC = segue.destinationViewController as! UserViewController
destinationVC.user = self.viewUser
}
}
}
Any ideas? If there is an issue with my tableView If statement, how can I fix it?
Thanks!
You can get the user object by indexPath, than pass it through the sender parameter of the performSegueWithIdentifier method
extension MatchesViewController: UITableViewDelegate
{
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
let user:PFUser?
if PFUser.currentUser()!.objectId == self.user1.objectId{
user = matchesResults[indexPath.row]["user2"] as! PFUser
}
if PFUser.currentUser()!.objectId == self.user2.objectId{
user = matchesResults[indexPath.row]["user1"] as! PFUser
}
self.performSegueWithIdentifier("UserSegue", sender: user)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// sender is the user object
if (segue.identifier == "UserSegue") {
let destinationVC = segue.destinationViewController as! UserViewController
destinationVC.user = sender // maybe you need cast sender to UserObject
}
}
}