David Sanford David Sanford - 3 months ago 10
Swift Question

IndexPath for variable row

I am using a UITableView with prototype cells. The main TableView is DiveDetails2VC and the prototype cell is based on DiveItemViewController via segue.

I need to save to parse the results, and have been able to save only row 0 to parse. I do not know how to set this up so that any row selected in the tableview is sent to parse. I am aware this is caused by the line in saveEntry:

let indexPath = NSIndexPath(forRow: 0, inSection: 0)


but I do not know how to set the forRow statement to allow any row within the displayed array. There is only one section.

DiveItemViewController

class DiveItemViewController: UITableViewController, ItemDataProtocol
{

private let NumberOfSections: Int = 1

// MARK: - Public Properties

//
// This property is an object that conforms to the ItemDataSelectedProtocol. We use it to call the
// selectedItem method.
//
var itemDataSelectedDelegate: AnyObject?


private var itemData: Array<String> = Array<String>()


override func viewDidLoad()
{
super.viewDidLoad()

// Adds "+" to dive item selection so divers can add another item to the selected list

navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(DiveItemViewController.AddItemButton(_:)))
}

override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}

// ---------------------------------------------------------------------------------------------
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: UITableViewCell! = tableView.dequeueReusableCellWithIdentifier(Resource.DiveItemCell)

if self.itemData.isEmpty == false
{
cell.textLabel?.text = itemData[indexPath.row]
}

parseItem = cell.textLabel!.text!

return cell
}

override func numberOfSectionsInTableView(tableView: UITableView) -> Int
{
return self.NumberOfSections
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
return itemData.count
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{

tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.Checkmark
if self.itemDataSelectedDelegate?.respondsToSelector(#selector(DiveDetails2VC.itemDataSelectedItem(_:))) != nil
{
(self.itemDataSelectedDelegate as! ItemDataSelectedProtocol).itemDataSelectedItem(indexPath.row)
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

override func tableView(tableView: UITableView, willDeselectRowAtIndexPath indexPath: NSIndexPath) -> NSIndexPath?
{
tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.None

return indexPath
}

func appendData(data: Array<String>) {

}


@IBAction func saveEntry (sender: AnyObject) {

let indexPath = NSIndexPath(forRow: 0, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(indexPath)

let updateDivelog2Query = PFQuery(className: "divelog")
updateDivelog2Query.whereKey("uuid", equalTo: diveUUID)
updateDivelog2Query.getFirstObjectInBackgroundWithBlock {(objects: PFObject?, error: NSError?) -> Void in

if let updateDivelog2Object = objects {

updateDivelog2Object.setValue (self.itemData[indexPath.row], forKey: cell!.textLabel!.text!)

updateDivelog2Object.pinInBackground()
updateDivelog2Object.saveInBackgroundWithBlock {(done:Bool, error:NSError?) in

if done {
print ("ParseData UPDATED data saved")

} else {
updateDivelog2Object.saveEventually()
}
}}}


}

func itemTitle(title: String)
{
self.navigationItem.title = title
}

@IBAction func AddItemButton (sender: AnyObject) {


let alert = UIAlertController(title: "Add item",
message: "Add a new Item to your list",
preferredStyle: .Alert)

let saveAction = UIAlertAction(title: "Save",
style: .Default,
handler: { (action:UIAlertAction) -> Void in

let textField = alert.textFields!.first
self.itemData.append(textField!.text!)
self.tableView.reloadData()
self.appendData(self.itemData)

})

let cancelAction = UIAlertAction(title: "Cancel",
style: .Default) { (action: UIAlertAction) -> Void in
}

alert.addTextFieldWithConfigurationHandler {
(textField: UITextField) -> Void in
}

alert.addAction(saveAction)
alert.addAction(cancelAction)

presentViewController(alert,
animated: true,
completion: nil)

tableView.reloadData()

}


func itemData(data: Array<String>)
{
self.itemData = data
}
}

Answer

Declare a var in your viewController:

var selectedIndexPath: NSIndexPath?

And then in your didSelectRowAtIndexPath, set this var with the selected indexPath like:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
{
    if let _ = self.selectedIndexPath {
        selectedIndexPath = indexPath
    }else{
        selectedIndexPath = NSIndexPath(forRow: indexPath.row, inSection: indexPath.section)
    }
    tableView.cellForRowAtIndexPath(indexPath)?.accessoryType = UITableViewCellAccessoryType.Checkmark
    if self.itemDataSelectedDelegate?.respondsToSelector(#selector(DiveDetails2VC.itemDataSelectedItem(_:))) != nil
    {
        (self.itemDataSelectedDelegate as! ItemDataSelectedProtocol).itemDataSelectedItem(indexPath.row)
    }
    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

And then use this selectedIndexPath like this in your saveEntry method:

@IBAction func saveEntry (sender: AnyObject) {   
    if let indexPath = selectedIndexPath {
       let cell = tableView.cellForRowAtIndexPath(indexPath)
       ...
    } 
}

EDIT: Added ")" behind "inSection: indexPath.section)"

Comments