使用 UserDefaults 更新数据模型

Updating a data model with UserDefaults

我正在使用集合视图来显示大约 30 个不同的单元格。每个单元格代表一项冬季运动。这些单元格由静态数据模型填充,并且它们会在每次应用程序更新时更新(无数据库)。

由于我一直在添加运动列表,因此我想在添加的最新运动上显示 "NEW" 徽章。当用户点击该特定运动时,"NEW" 徽章消失并通过 UserDefaults 持续存在。屏幕截图如下:

我的进度如下。我只是坚持坚持 "new" 属性 所以一旦 "new" 运动被点击,bool 更改为 false 并在 UserDefaults 中更新。

Model. 我将在此处更新新标志。如果为真,它将显示徽章(最终将取消隐藏图像视图。

struct WinterModel {
    let sportName: String
    var new: Bool
}

struct WinterData {
    static func allSports() -> [WinterModel] {
        return [
            WinterModel(sportName: "Luge", new: true),
            WinterModel(sportName: "Curling", new: false),
            WinterModel(sportName: "Skeleton", new: false),
            WinterModel(sportName: "Speed Skating", new: false),
            WinterModel(sportName: "Bobsleigh", new: false)
            // 30+ more
        ]
    }
}

主要VC.填充集合视图。

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    var winter = WinterData.allSports()

    @IBOutlet weak var sportCollectionView: UICollectionView!

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return winter.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ID", for: indexPath as IndexPath) as! WinterSportCell
        let sport = winter[indexPath.item]
        cell.sport = sport
        return cell
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        sportCollectionView.dataSource = self
        sportCollectionView.delegate = self
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        // Cell was changed... Change data model to false?
    }

}

最后,UICollectionViewCell

class WinterSportCell: UICollectionViewCell { 
    @IBOutlet weak var sportNameLabel: UILabel!
    @IBOutlet weak var newOutlet: UILabel!
    var sport: WinterModel! {
        didSet {
            self.updateUI()
        }
    }
    func updateUI() {
        sportNameLabel.text = sport.sportName
        if sport.new {
            newOutlet.isHidden = false
        } else {
            newOutlet.isHidden = true
        }
    }
}

如何配置 UserDefaults,以便在用户点击该单元格时数据模型的 'new' 属性 更新为 false?

您可以添加 属性 id 或检查 winterModel.name 以更新 属性 新的。您需要使用 codable 将您的模型保存到 UserDefault。

struct WinterModel: Codable {
    var id: Int
    let sportName: String
    var new: Bool
}

struct WinterDefaults {

    private static let winterDefaults = UserDefaults.standard
    private static let key = "Winter"
    private static let decoder = JSONDecoder()
    private static let encoder = JSONEncoder()
    private init() {}

    static func getWinterModels() -> [WinterModel]? {

        var winterModel: [WinterModel]?
        if let data = UserDefaults.standard.value(forKey: key) as? Data {
            winterModel = try? decoder.decode([WinterModel].self, from: data)
        }

        return winterModel
    }

    static func saveWinterModels(with winter: [WinterModel]) {
        let data = try? encoder.encode(winter)
        winterDefaults.set(data, forKey: key)
    }

    static func updateWinterModels(with winter: WinterModel) {

        var winterModels = getWinterModels()

        if winterModels != nil {

            for i in 0..<winterModels!.count {
                if winterModels?[i].id == winter.id {
                    winterModels?[i].new = false
                }
            }

            saveWinterModels(with: winterModels!)
        }
    }

}

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    @IBOutlet weak var sportCollectionView: UICollectionView!

    var winterList: [WinterModel]?

    override func viewDidLoad() {
        super.viewDidLoad()

        sportCollectionView.dataSource = self
        sportCollectionView.delegate = self

        if let winters = WinterDefaults.getWinterModels() {
            winterList = winters
        } else {
            let winters = getWinterList()
            winterList = winters
            WinterDefaults.saveWinterModels(with: winters)
        }

    }

    func getWinterList() -> [WinterModel] {
        return [
            WinterModel(id: 0, sportName: "Luge", new: true),
            WinterModel(id: 1, sportName: "Curling", new: false),
            WinterModel(id: 2, sportName: "Skeleton", new: false),
            WinterModel(id: 3, sportName: "Speed Skating", new: false),
            WinterModel(id: 4, sportName: "Bobsleigh", new: false)
        ]
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return winterList?.count ?? 0
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ID", for: indexPath as IndexPath) as? WinterSportCell else {
            return UICollectionViewCell()
        }

        if let winter = winterList?[indexPath.row] {
            cell.sport = winter
        }

        return cell

    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if winterList != nil {
            winterList![indexPath.row].new = false
            sportCollectionView.reloadData()
            WinterDefaults.saveWinterModels(with: winterList!)
        }
    }

}

class WinterSportCell: UICollectionViewCell {
    @IBOutlet weak var sportNameLabel: UILabel!
    @IBOutlet weak var newOutlet: UILabel!
    var sport: WinterModel! {
        didSet {
            sportNameLabel.text = sport.sportName
            newOutlet.isHidden = sport.new
        }
    }
}