【问题标题】:Reload specific tableview cell with updating array model locally重新加载特定的 tableview 单元格并在本地更新数组模型
【发布时间】:2019-10-22 23:21:00
【问题描述】:

我正在开发一个应用程序,其中电子邮件列表显示在表格视图中。每封电子邮件都包含来自三个状态的状态之一,例如已付款、待处理和争议。这些数据来自网络服务响应。如果电子邮件状态已支付,那么我可以通过单击待处理或争议按钮将状态更改为待处理或争议。如果状态已支付,则用户无法对已支付按钮执行任何操作。

现在假设我通过调用 web 服务将电子邮件状态从待处理更改为已付款,此时我想重新加载该特定单元格并在本地替换该模型的状态。

我怎样才能做到这一点。

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell : HomeTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier) as! HomeTableViewCell
    if arrayData.count > 0 && arrayData.count > indexPath.row {
    var objemail = self.arrayData.object(at: indexPath.row) as? NewHomeModel
    if objemail?.unread == 1 {
        cell.lblEmailSender.textColor = UIColor.black
        cell.lblEmailDescription.textColor = UIColor.black
    }else{
        cell.lblEmailSender.textColor = UIColor.gray
        cell.lblEmailDescription.textColor = UIColor.gray
    }
    if objemail?.fileStatus == 1 {
        cell.imgAttachment.isHidden = false
    }else{
        cell.imgAttachment.isHidden = true
    }
    cell.lblEmailSender.text = objemail?.from
    cell.lblEmailHeading.text = objemail?.subject
    cell.lblEmailDescription.text = objemail?.body
    var pending = objemail?.pending
    if (pending == 0) {
        cell.btnPending.setBackgroundImage(UIImage(named: "pending_disable_icon"), for: UIControl.State.normal)
        cell.btnPending.addTarget(self, action: #selector(HomeViewController.penddingClick(_:)), for:.touchUpInside )
    }
    else
    {
        cell.btnPending.setBackgroundImage(UIImage(named: "pending_active_icon"), for: UIControl.State.normal)
    }
    if objemail?.dispute == 0 {
        cell.btnDispute.setBackgroundImage(UIImage(named: "dispute_disable_icon"), for: UIControl.State.normal)
        cell.btnDispute.addTarget(self, action: #selector(HomeViewController.disputeClick(_:)), for:.touchUpInside )
    }
    else
    {
        cell.btnDispute.setBackgroundImage(UIImage(named: "dispute_active_icon"), for: UIControl.State.normal)
    }
    if(objemail?.paid == 0)
    {
        cell.btnPaid.setBackgroundImage(UIImage(named: "paid_disable_icon"), for: UIControl.State.normal)
        cell.btnPaid.addTarget(self, action: #selector(HomeViewController.paidClick(_:)), for:.touchUpInside )
    }
    else
    {
        cell.btnPaid.setBackgroundImage(UIImage(named: "paid_active_icon"), for: UIControl.State.normal)

    }
    }
    return cell
}
struct NewHomeModel {
var body: String?
var date : String?
var dispute: Int?
var fileStatus: Int?
var from: String?
var msg_id: String?
var paid: Int?
var pending: Int?
var subject: String?
var thread_id: String?
var unread : Int?
var nextToken : String?

init(jsonData: [String: Any]) {
    body = jsonData["body"] as? String ?? ""
    date = jsonData["date"] as? String ?? ""
    dispute = jsonData["dispute"] as? Int ?? 0
    fileStatus = jsonData["fileStatus"] as? Int ?? 0
    from = jsonData["from"] as? String ?? ""
    msg_id = jsonData["msg_id"] as? String ?? ""
    paid = jsonData["paid"] as? Int ?? 0
    pending = jsonData["pending"] as? Int ?? 0
    subject = jsonData["subject"] as? String ?? ""
    thread_id = jsonData["thread_id"] as? String ?? ""
    unread = jsonData["unread"] as? Int ?? 0
}}

【问题讨论】:

    标签: ios arrays swift uitableview


    【解决方案1】:

    让我们假设您的 Email 模型看起来像,

    class Email {
        var message: String
        var state: CellState
    
        init(message: String, state: CellState) {
            self.message = message
            self.state = state
        }
    }
    

    其中CellState 是一个enum,它代表states 的cell - paid, pending, dispute,即

    enum CellState {
        case paid, pending, dispute
    }
    

    首先,你不能在tableView(_:cellForRowAt:)方法中写cell的配置代码。 cell's 配置必须写入cell 本身,即

    class HomeTableViewCell: UITableViewCell {
        var buttonTapHandler: (()->())?
        private var email: Email?
    
        func configure(with email: Email) {
            self.email = email
            switch email.state {
            case .paid:
                self.backgroundColor = #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1)
            case .pending:
                self.backgroundColor = #colorLiteral(red: 0.9529411793, green: 0.6862745285, blue: 0.1333333403, alpha: 1)
            case .dispute:
                self.backgroundColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1)
            }
        }
    
        @IBAction func onTapPendingButton(_ sender: UIButton) {
            if self.email?.state != .pending {
                self.email?.state = .pending
                self.buttonTapHandler?()
            }
        }
    
        @IBAction func onTapDisputeButton(_ sender: UIButton) {
            if self.email?.state != .dispute {
                self.email?.state = .dispute
                self.buttonTapHandler?()
            }
        }
    
        @IBAction func onTapPaidButton(_ sender: UIButton) {
            if self.email?.state != .paid {
                self.email?.state = .paid
                self.buttonTapHandler?()
            }
        }
    }
    

    在上面的代码中,

    1. buttonTapHandler - 每当cell's state 在点击任何paid/pending/dispute buttons 后更改时,处理reload 的cell。我们将看看如何进一步使用它。

    2. configure(with:) - 基于其current state 处理cell 的UI。

    3. button tap actions - 更改cell's state,基于button 被窃听。还调用buttonTapHandler 来更新UI。

    您的ViewController 看起来像,

    class VC: UIViewController, UITableViewDataSource {
        var emails = [Email]()
        //rest of the code....
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return self.emails.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! HomeTableViewCell
            let email = self.emails[indexPath.row]
            cell.configure(with: email)
            cell.buttonTapHandler = {
                DispatchQueue.main.async {
                    tableView.reloadRows(at: [indexPath], with: .none)
                }
            }
            return cell
        }
    }
    

    在上面的代码中,最重要的是我们设置cell'sbuttonTapHandler,即

    cell.buttonTapHandler = {
        DispatchQueue.main.async {
            tableView.reloadRows(at: [indexPath], with: .none)
        }
    }
    

    每次您在cell 中点击button indexPath 时都会调用此handler,而特定的cell 将是reloaded。

    【讨论】:

    • 是的,我做到了。但是您必须使用enum 来识别您的state 而不是Int。这在这里更相关
    【解决方案2】:

    您可以在本地重新加载模型数据,然后调用 tableView.reloadRows(at: IndexPath, with: UITableViewRowAnimation) 将使用您在模型对象上更新的新数据重新加载单元格。

    【讨论】:

      【解决方案3】:

      你可以使用reloadRows(at:with:):

      tableView.reloadRows(at: [indexPathOfTheCellToBeReloaded], with: .automatic)
      

      这是 Swift 代码。不确定您需要什么,因为您在标签中同时指定了 Swift 和 Objective-C。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-17
        • 1970-01-01
        • 2018-07-31
        • 1970-01-01
        • 2012-05-25
        • 2018-10-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多