如何修改 cellForRowAt 之外的单元格 Swift

How to modify a cell outside cellForRowAt Swift

目前我的代码是这样的,我在单元格中设置了一个日期选择器

代码 A 有效

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = Bundle.main.loadNibNamed("DailyTimesTableViewCell", owner: self, options: nil)?.first as! DailyTimesTableViewCell
    cell.endTimeTapped = { (button) -> DailyTimesTableViewCell in
        cell.datePicker.date = self.convertToDateObject(timeString: endTime as! String)
    } 
    return cell
}

我想根据一些逻辑修改单元格中的 datePicker,所以当我尝试下面的代码 B 时,使用回调修改单元格中的 datePicker setTimeInDatePicker 它似乎没有工作。

请指教我可能哪里出错了。

代码 B:不起作用

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = Bundle.main.loadNibNamed("DailyTimesTableViewCell", owner: self, options: nil)?.first as! DailyTimesTableViewCell
    cell.endTimeTapped = { (button) -> DailyTimesTableViewCell in
    self.setTimeInDatePicker(time: endTime!, cell: cell){ modifiedCell in
                    return modifiedCell
                }
    } 
    return cell
}


func setTimeInDatePicker(time: String, cell: DailyTimesTableViewCell, completionHandler: @escaping(DailyTimesTableViewCell) -> DailyTimesTableViewCell) {

    tableView.beginUpdates()
    let row     = cell.tag
    let rows    = self.timesArray.count

    if self.startTimeHighlighted{
        // Setting minimum startTime for datePicker
        if row == 0{ // For first row
            let minStartTimeString      =   "0:05 am"
            cell.datePicker.minimumDate = self.convertToDateObject(timeString: minStartTimeString)
        }
        else if row > 0 {   // For remaining rows
            let endTimeStringOfPreviousCell = self.timesArray[row - 1]["endTime"]!
            let endTimeObjectOfPreviousCell = self.convertToDateObject(timeString: endTimeStringOfPreviousCell)
            cell.datePicker.minimumDate     = endTimeObjectOfPreviousCell
        }

        // Setting maximum startTime for datepicker
        let endTimeString           =   self.timesArray[row]["endTime"]!
        let endTimeObject           =   self.convertToDateObject(timeString: endTimeString)
        let maxStartTimeObject      =   endTimeObject.addingTimeInterval(-5 * 60.0)            // removing 5mins
        cell.datePicker.maximumDate =   maxStartTimeObject

        // Setting selected date in as startTime title
        let dateString = self.convertDateToString(cell.datePicker.date)
        cell.startTime.setTitle(dateString, for: .normal)

        // Saving updated date to the timesArray
        self.timesArray[row]["startTime"] = dateString
        //print("endTime in DatePickerChanged: \(self.timesArray[row]["endTime"])")
        print("timesArray when startTimeHighlighted: \(self.timesArray)")
        completionHandler(cell)

    }
    else if self.endTimeHighlighted{
        print("datePicker changed 3")
        // Setting minimum endTime for datePicker

        let startTimeString = self.timesArray[row]["startTime"]
        let startTimeObject       =   self.convertToDateObject(timeString: startTimeString!)
        let minEndTimeObject    =   startTimeObject.addingTimeInterval(5 * 60.0)            // adding 5mins
        cell.datePicker.minimumDate = minEndTimeObject

        // Setting maximum endTime for datePicker
        if rows == 1 || row + 1 == self.timesArray.count{ // For first and last row
            let maxEndTimeString = "11:55 pm"
            cell.datePicker.maximumDate = self.convertToDateObject(timeString: maxEndTimeString)
        }
        else{ // If more than one row
            let nextCellStartTime           =   self.timesArray[row + 1]["startTime"]!
            let nextCellStartTimeObject     =   self.convertToDateObject(timeString: nextCellStartTime)
            cell.datePicker.maximumDate     =   nextCellStartTimeObject
        }

        // Setting selected date in as endTime title
        let dateString = self.convertDateToString(cell.datePicker.date)
        cell.endTime.setTitle(dateString, for: .normal)

        // Saving updated date to the timesArray
        self.timesArray[row]["endTime"] = dateString
        print("timesArray when endTimeHighlighted: \(self.timesArray)")

        completionHandler(cell)

    }

    tableView.endUpdates()

}

您似乎将 completionHandlers 与其他东西混淆了。

通常在任务异步时使用 completionHandlers。所以简而言之,你开始一个任务(通常是网络),当它完成时(这可能需要很长时间)你有一个处理程序可以调用让应用程序知道它已经完成。

由于应用程序没有等待这个非常长的异步任务完成,它继续 运行 并且与任务首次启动时的状态不同。简而言之,无论您在完成处理程序中 returning will/should 都不会被使用。

基于此,以及一切似乎都是同步的事实,您可以像这样重构您的函数:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = Bundle.main.loadNibNamed("DailyTimesTableViewCell", owner: self, options: nil)?.first as! DailyTimesTableViewCell
    cell.endTimeTapped = { [unowned self](_) in
        // Use unowned to make sure you don't create a retain-cycle
        self.setTimeInDatePicker(time: endTime!, cell: cell)
    } 
    return cell
}


func setTimeInDatePicker(time: String, cell: DailyTimesTableViewCell) {

    let row     = cell.tag
    let rows    = self.timesArray.count

    if self.startTimeHighlighted{
        // Setting minimum startTime for datePicker
        if row == 0{ // For first row
            let minStartTimeString      =   "0:05 am"
            cell.datePicker.minimumDate = self.convertToDateObject(timeString: minStartTimeString)
        }
        else if row > 0 {   // For remaining rows
            let endTimeStringOfPreviousCell = self.timesArray[row - 1]["endTime"]!
            let endTimeObjectOfPreviousCell = self.convertToDateObject(timeString: endTimeStringOfPreviousCell)
            cell.datePicker.minimumDate     = endTimeObjectOfPreviousCell
        }

        // Setting maximum startTime for datepicker
        let endTimeString           =   self.timesArray[row]["endTime"]!
        let endTimeObject           =   self.convertToDateObject(timeString: endTimeString)
        let maxStartTimeObject      =   endTimeObject.addingTimeInterval(-5 * 60.0)            // removing 5mins
        cell.datePicker.maximumDate =   maxStartTimeObject

        // Setting selected date in as startTime title
        let dateString = self.convertDateToString(cell.datePicker.date)
        cell.startTime.setTitle(dateString, for: .normal)

        // Saving updated date to the timesArray
        self.timesArray[row]["startTime"] = dateString
        //print("endTime in DatePickerChanged: \(self.timesArray[row]["endTime"])")
        print("timesArray when startTimeHighlighted: \(self.timesArray)")

    }
    else if self.endTimeHighlighted{
        print("datePicker changed 3")
        // Setting minimum endTime for datePicker

        let startTimeString = self.timesArray[row]["startTime"]
        let startTimeObject       =   self.convertToDateObject(timeString: startTimeString!)
        let minEndTimeObject    =   startTimeObject.addingTimeInterval(5 * 60.0)            // adding 5mins
        cell.datePicker.minimumDate = minEndTimeObject

        // Setting maximum endTime for datePicker
        if rows == 1 || row + 1 == self.timesArray.count{ // For first and last row
            let maxEndTimeString = "11:55 pm"
            cell.datePicker.maximumDate = self.convertToDateObject(timeString: maxEndTimeString)
        }
        else{ // If more than one row
            let nextCellStartTime           =   self.timesArray[row + 1]["startTime"]!
            let nextCellStartTimeObject     =   self.convertToDateObject(timeString: nextCellStartTime)
            cell.datePicker.maximumDate     =   nextCellStartTimeObject
        }

        // Setting selected date in as endTime title
        let dateString = self.convertDateToString(cell.datePicker.date)
        cell.endTime.setTitle(dateString, for: .normal)

        // Saving updated date to the timesArray
        self.timesArray[row]["endTime"] = dateString
        print("timesArray when endTimeHighlighted: \(self.timesArray)")

    }

}

请注意 endTimeTapped 闭包如何使 [unowned self] 的用户避免保留循环。

您还可以注意到 beginUpdate/endUpdate 已被删除。原因是您没有做任何影响相关单元格高度的事情,您只是更改日期,因此您不需要触发 tableView 的刷新,因为更改将自动应用。

检查一下是否对您有所帮助?!

N.B。该单元格是 class,您作为参数发送给 setTimeInDatePicker 的内容是对它的引用,因此您实际上不需要 return 任何东西,所以您已经拥有了它。

如果我理解正确的话,您只是希望能够在一些回调之后或在其他一些函数中弄乱一个单元格。您可以随时使用 tableView.cellForRow(at: IndexPath) 来完成此目标。请注意,此函数 returns 是 UITableViewCell 而不是您拥有的任何自定义单元格类型,因此您必须将其转换为 (cell as? YourCustomCellClass)?.whateverFunctionOrPropertyHere。考虑一下您希望如何传递您的信息 - 在单元格上设置一个完成块是个不错的主意,但还有其他方法可以做到这一点。