首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何通过按钮更新自定义单元格中分配给索引路径的核心数据

如何通过按钮更新自定义单元格中分配给索引路径的核心数据
EN

Stack Overflow用户
提问于 2018-08-09 12:44:49
回答 1查看 692关注 0票数 0

我有一个应用程序的类型“做清单”,我想检查我的项目在清单上与自定义按钮复选标记。应用程序的结构如下:主列表使用带有自定义TableViewCell的UIButton "checkmarkButton“和标签"cellLabel”的UIButton。它们的值在创建后保存到核心数据,checkmarkButton默认状态为false,并使用值(forKeyPath:)分配给cellForRowAtindexPath中的单元格。在TableViewCell类中,我有一个checkmarkBtnTapped函数,它更改按钮的显示图像(check/uncheck),将该图像着色到指定的颜色,并在CoreData属性中将按钮"state“更新为bool,用于其键路径,获取CoreData和reloadTableView。一些函数使用我的列表数组和来自核心数据或表视图的其他东西来自UITableViewController,所以我为它们实现了委托。

问题是,当我点击checkmarkButton并使用updateBtnState新建行时,它使用的是已更改的状态(即,我点击了状态为"false“的带有按钮的行,我实际的带标签的行仍然在"false”上,新行中添加了空标签,并添加了状态为“true”的按钮)--我猜这是由于只引用managedObjectContext而不是indexPath的updateBtnState()方法。但是,当我试图将项作为indexPath而不是NSManagedObject的一点引用时,由于IndexPath参数的原因,不能将该函数传递给TableViewCell类。在下面的TableViewController.swift中,我留下了updateBtnState2(),我认为它可以解决我的问题,但是在TableViewCell checkmarkBtnTapped()函数中是不可用的。

TableViewController.swift

导入UIKit导入CoreData

类TableViewController: UITableViewController,ButtonSelectionDelegate {

代码语言:javascript
运行
复制
var list: [NSManagedObject] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.title = "List"

        navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addTapped))

        let cellNib = UINib(nibName: "TableViewCell", bundle: nil)
       self.tableView.register(cellNib, forCellReuseIdentifier: "cell")   
    }

override func viewWillAppear(_ animated: Bool) {
    UIApplication.shared.statusBarStyle = .lightContent
    fetch()    
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    UIApplication.shared.statusBarStyle = UIStatusBarStyle.default
}

func save(name: String, state: Bool) {
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let managedObjectContext = appDelegate.persistentContainer.viewContext
    let entity =
        NSEntityDescription.entity(forEntityName: "Item", in: managedObjectContext)!
    let Item = NSManagedObject(entity: entity, insertInto: managedObjectContext)

    Item.setValue(name, forKeyPath: "name")
    Item.setValue(state, forKeyPath: "isChecked")
    do{
        try managedObjectContext.save()
        list.append(Item)
    } catch let error as NSError {
        print("Could not save. \(error), \(error.userInfo)")
    }
}

func fetch(){
    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
        return
    }
    let managedObjectContext = appDelegate.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Item")
    do{
        list = try managedObjectContext.fetch(fetchRequest)
    } catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
    }
}

func updateBtnState(state: Bool){

    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let managedObjectContext = appDelegate.persistentContainer.viewContext
    let entity = NSEntityDescription.entity(forEntityName: "Item", in: managedObjectContext)!
    let Item = NSManagedObject(entity: entity, insertInto: managedObjectContext)

    Item.setValue(state, forKeyPath: "isChecked")

    do{
        try managedObjectContext.save()
    } catch let error as NSError {
        print("Couldnt update. \(error)")
    }
}

func updateBtnState2(indexPath: IndexPath, state: Bool){

    guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
    let managedObjectContext = appDelegate.persistentContainer.viewContext
    let item = list[indexPath.row]

    item.setValue(state, forKeyPath: "isChecked")

    do{
        try managedObjectContext.save()
        list[indexPath.row] = item
    } catch let error as NSError {
        print("Couldnt update. \(error)")
    }
}

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
        let item = list[indexPath.row]
        cell.selectionDelegate = self
        cell.cellLabel.text = item.value(forKeyPath: "name") as? String
        cell.checkmarkButton.isSelected = item.value(forKeyPath: "isChecked") as! Bool
        return cell
    }

func updateTableView(){
    tableView.reloadData()
}

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }

@objc func addTapped(){

        let alert = UIAlertController(title: "New Name", message: "Add a new name", preferredStyle: .alert)

        let saveAction = UIAlertAction(title: "Save", style: .default) {
            [unowned self] action in
            guard let textField = alert.textFields?.first,
                let nameToSave = textField.text else {
                    return
            }
            self.save(name: nameToSave, state: false)
            self.tableView.reloadData()
        }

        let cancelAction = UIAlertAction(title: "Cancel", style: .default)
        alert.addTextField()
        alert.addAction(cancelAction)
        alert.addAction(saveAction)
        present(alert, animated: true)
    }

TableViewCell.swift

代码语言:javascript
运行
复制
import UIKit


protocol ButtonSelectionDelegate: class {
    func fetch()
    func updateTableView()
    func updateBtnState(state: Bool)
}

class TableViewCell: UITableViewCell  {
    weak var selectionDelegate: ButtonSelectionDelegate!
    @IBOutlet var checkmarkButton: UIButton!
    @IBOutlet var cellLabel: UILabel!
    @IBAction func checkmarkBtnTapped(_ sender: UIButton) {
      sender.isSelected = !sender.isSelected
        if sender.isSelected {
            selectionDelegate?.updateBtnState(state: true)
            let image: UIImage? = UIImage(named: "done_icon.png")?.withRenderingMode(.alwaysTemplate)
            checkmarkButton.setImage(image, for: .normal)
            checkmarkButton.tintColor = UIColor( red: CGFloat(21/255.0), green: CGFloat(126/255.0), blue: CGFloat(251/255.0), alpha: CGFloat(1.0))
            selectionDelegate?.fetch()
           selectionDelegate?.updateTableView()
            print("checkmarkButton pressed to done")
        } else {
            selectionDelegate?.updateBtnState(state: false)
            let image: UIImage? = UIImage(named: "undone_icon.png")?.withRenderingMode(.alwaysTemplate)
            checkmarkButton.setImage(image, for: .normal)
            checkmarkButton.tintColor = UIColor.gray
            selectionDelegate?.fetch()
            selectionDelegate?.updateTableView()
            print("checkmarkButton pressed to undone")
        }
    }

     override func layoutSubviews() {
     super.layoutSubviews()
    let image: UIImage? = UIImage(named: "undone_icon.png")?.withRenderingMode(.alwaysTemplate)
     checkmarkButton.setImage(image, for: .normal)
     checkmarkButton.tintColor = UIColor.gray
     } 

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }
}

extension UIButton {
    func hasImage(named imageName: String, for state:     UIControlState) -> Bool {
        guard let buttonImage = image(for: state), let namedImage = UIImage(named: imageName) else {
            return false
        }
        return UIImagePNGRepresentation(buttonImage) == UIImagePNGRepresentation(namedImage)
    }
}
EN

回答 1

Stack Overflow用户

发布于 2018-08-09 14:19:26

使用表视图单元格和集合视图单元格的最佳方法是让该单元格负责其UI的所有配置。要做到这一点,您可以将数据传递给单元格,然后将正确的数据放入按需要格式化的正确数据中。您已经有了一个自定义的UITableViewCell,所以这很容易实现…

代码语言:javascript
运行
复制
// Make the to-do item's property names into strings so you can't mistype them later.
// The other option would be to create the subclass of NSManagedObject so the properties are directly accessible.
let isChecked = "isChecked"
let name = "name"

class TableViewCell: UITableViewCell  {
    // Add a property to hold the actual to-do item
     var item: NSManagedObject? {
         didSet {
             updateCell()
        }
    }
    // Make all outlets private so you aren't tempted to touch them from outside
    @IBOutlet private var checkmarkButton: UIButton!
    @IBOutlet private var cellLabel: UILabel!
    // Create both images once for each cell rather than every time the image changes
     let doneImage = UIImage(named: "done_icon.png")?.withRenderingMode(.alwaysTemplate)
     let notDoneImage = UIImage(named: "undone_icon.png")?.withRenderingMode(.alwaysTemplate)

     let doneColor = UIColor( red: CGFloat(21/255.0), green: CGFloat(126/255.0), blue: CGFloat(251/255.0), alpha: CGFloat(1.0))
     let notDoneColor = UIColor.gray

     private func updateCell() {
         guard let item = item else { return }
         cellLabel?.text = item.value(forKeyPath: name) as? String
         checkmarksButton?.isSelected = item.value(forKeyPath: isChecked) as! Bool
    }

    @IBAction private func checkmarkBtnTapped(_ sender: UIButton) {
        // Safely unwrap the to-do item
         guard let item = item else { return }
         sender.isSelected = !sender.isSelected
         let selected = sender.isSelected
         item.setValue(selected, forKeyPath: "isChecked")
         checkmarkButton.setImage(selected ? doneImage : notDoneImage, for: .normal)
         checkmarkButton.tintColor = selected ? doneColor : notDoneColor
         print("checkmarkButton pressed to \(selected ? "done" : "undone")")
    }

     …
}

这样,单元格就可以直接更新托管对象,而不是试图通过视图控制器重新连接到它。

而且,layoutSubviews中的代码不应该是真正需要的,但是如果是的话,awakeFromNib是放置它的更好地方。

一旦单元格完成,您就可以摆脱这些更新按钮函数,并将cellForRowAt更改为…。

代码语言:javascript
运行
复制
class TableViewController: UITableViewController {
    …

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
         let item = list[indexPath.row]
         cell.item = item
         return cell
    }

    …
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51767429

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档