2
votes

I have a UITableView in my ViewController. One of the cell could be tap into another TableViewController to allow select a value.

I want to update my cell after back from the callee ViewController.

right now, i could pass back the selected value by delegate.

However, i tried following way, none of them works.

  1. self.mainTable.reloadData()

  2.     dispatch_async(dispatch_get_main_queue()) {
        self.mainTable.reloadData()
    }
    
  3.     self.mainTable.beginUpdates()
    self.mainTable.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
    self.mainTable.endUpdates()
    

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { was called and executed without error.

but the UI just doesn't change

here is the way I update value in cellForRowAtIndexPath

            if let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell! {
            currentCell.textLabel?.text = address
            return currentCell
        }

Here is my cellForRowAtIndexPath -

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let id = "Cell"
        println(indexPath)

        if indexPath.row == 1 {
            var cell = tableView.dequeueReusableCellWithIdentifier(id) as? UITableViewCell

            if cell == nil {
                cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: id)

                cell?.contentMode = UIViewContentMode.Center
                cell?.selectionStyle = UITableViewCellSelectionStyle.None
                cell?.contentView.addSubview(mapView!)

            }
            return cell!
        }else{

            let cell = UITableViewCell()
            cell.textLabel?.text = self.address

            return cell
        }
    }

Here is the delegate method -

func passBackSelectedAddress(address: String) { 
    self.address = address 
    var indexPath = NSIndexPath(forRow: 0, inSection: 0)
    self.mainTable.beginUpdates()    
    self.mainTable.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) 
    self.mainTable.endUpdates() 
}

My fix: After more debug, i find the cause, the self.address value is updated in delegate, however it roll back to previous value in cellForRowAtIndexPath.

I change the property to a static property, then resolve the problem. I'm not sure what's wrong with instance property, and why it reverses back.

static var _address:String = ""

2
Don't call cellForRowAtIndexPath in cellForRowAtIndexPath. You need to update your data model and then let the normal code in cellForRowAtIndexPath do its thing.Paulw11
my model is just a simple String variable, i didn't call it at itself. i call it at my delegate // MARK: delegate func passBackSelectedAddress(address: String){ self.address = address var indexPath = NSIndexPath(forRow: 0, inSection: 0) self.mainTable.beginUpdates() self.mainTable.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) self.mainTable.endUpdates() }Huan Jiang
Are you sure your delegate is being called? Can you show your full cellForRowAtIndexPath method?Paulw11
i'm sure it is called, i set the breakpoint, and it stopped. here is the code pastie.org/10406140Huan Jiang
Please edit your question to include the codePaulw11

2 Answers

1
votes

It seems like you're trying to grab a cell from the UITableView and then update the textLabel value that way. However, UITableView and UITableViewCell are not meant to be updated in this way. Instead, store the value of address in your class and update this value when the delegate calls back into your class. If cellForRowAtIndexPath constructs the UITableViewCell with the value of self.address, calling mainTable.reloadData() after should update the cell to the new value.

For example:

var address: String

func delegateCompleted(address: String) {
    self.address = address
    self.mainTable.reloadData()
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier(<your identifier>)

    if (indexPath == <your address cell indexPath>) {
        let textLabel = <get your textLabel from the cell>
        textLabel?.text = self.address
    }

    return cell
}
0
votes

Your cellForRowAtIndexPath has some problems -

  • You are using the same re-use identifier for different types of cell (one with a map, one without)
  • When you allocate the table view cell for the other row, you don't include the re-use identifier.
  • You have no way of referring to the map view that you are adding after the method exits because you don't keep a reference.

If you are using a storyboard then you should create the appropriate prototype cells and subclass(es) and assign the relevant cell reuse ids. If you aren't then I suggest you create a cell subclass and register the classes against the reuse identifiers. Your cellForRowAtIndexPath will then look something like -

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var returnCell:UITableViewCell


    if indexPath.row == 1 {
       var myMapCell = tableView.dequeueReusableCellWithIdentifier("mapCell", forIndexPath:indexPath) as MYMapCell

       myMapCell.contentMode = UIViewContentMode.Center
       myMapCell.selectionStyle = UITableViewCellSelectionStyle.None
       // Set the properties for a map view in the cell rather than assigning adding an existing map view
       returnCell=myMapCell
    }else{

         returnCell = tableView.dequeueReusableCellWithIdentifier("addressCell", forIndexPath:indexPath)
        returnCell.textLabel?.text = self.address

    }
    return returnCell;
}