如何使用全局变量数组实现 userDefaults

Posted

技术标签:

【中文标题】如何使用全局变量数组实现 userDefaults【英文标题】:How to implement userDefaults with a Global Variable array 【发布时间】:2020-05-14 21:35:29 【问题描述】:

我有一个空数组设置为全局变量,其中填充了表格视图中的数组项。这用于填充另一个表视图。这些数据需要持久化,以便当用户返回应用程序时,他们的 tableview 数据处于与离开时相同的状态,即使用数组中的数据填充。

虽然我已经寻找了几十个教程和示例。我自己也破解了它以使其工作,每次我重新加载应用程序时,数组都是空的。如何让该全局变量数组保留它的数组数据?

var sharedData = [String]()

这是我的第一个 VC,其中我有 UserDefaults 的设置功能。每次对数组进行更改时,我都会执行我的 saveArray() 函数。每次我需要从数组中加载时,我都会执行 retrieveArray() 函数。

import UIKit

var sharedData = [String]()
struct Keys 

    static let arrayKey = "arrayKey"


let defaults = UserDefaults.standard

func saveArray() 
    defaults.set(sharedData, forKey: Keys.arrayKey)


func retrieveArray() 
    var savedData = defaults.object(forKey: Keys.arrayKey) as? [String] ?? []
    savedData.append(contentsOf: sharedData)


class ViewController: UIViewController 

    var effect:UIVisualEffect!

    @IBOutlet weak var searchBar: UISearchBar!

    @IBOutlet var tableView: UITableView!

    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!

    @IBOutlet weak var visualEffectView: UIVisualEffectView!

    let materialData = ["One", "Two", "Three", "Four"]

    var searchMaterial = [String]()
    var searching = false

    @IBAction func favoritesButtonArrayUpdate(_ sender: UIBarButtonItem) 
        print(sharedData)

    

    override func viewDidLoad() 
        super.viewDidLoad()

    tableView.delegate = self
        tableView.dataSource = self

        saveArray()
        retrieveArray()

        print(sharedData)

    

extension ViewController: UITableViewDelegate 

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 

        tableView.deselectRow(at: indexPath, animated: true)
        print(self.materialData[indexPath.row], "selected!")
    

    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? 

        let favorite = UITableViewRowAction(style: .default, title: "Favorite")  (action, indexPath) in

            var data: String

            if self.searching 
                data = self.searchMaterial[indexPath.row]
             else 
                data = self.materialData[indexPath.row]
            

            sharedData.append(data)
            saveArray()
            print(sharedData)

        

        favorite.backgroundColor = UIColor.orange
        return [favorite] 
    


这是我的第二个 VC,它显示存储在全局变量数组 sharedData 中的数组数据。在对数组进行更改并从数组中提取数据时,我再次添加了所有 func。

import UIKit

class FavoritesViewController: UIViewController 

    @IBOutlet var tableView: UITableView!

    override func viewDidLoad() 
        super.viewDidLoad()

        saveArray()
        retrieveArray()
    


extension FavoritesViewController: UITableViewDelegate, UITableViewDataSource 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        retrieveArray()
        return sharedData.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        retrieveArray()
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.numberOfLines = 0
        cell.textLabel?.text = sharedData[indexPath.row]
        return cell
    

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool 
        return true
    

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) 
        if editingStyle == .delete 

            sharedData.remove(at: indexPath.row)
            saveArray()
            tableView.beginUpdates()
            tableView.deleteRows(at: [indexPath], with: .automatic)
            tableView.endUpdates()
        
    

【问题讨论】:

【参考方案1】:

问题可能出在这里:

let savedData: [String] = userDefaults.object(forKey: "arrayKey") as? [String] ?? []

尝试更改它:

let savedData: [String] = userDefaults?.object(forKey: "arrayKey") as? [String] ?? []

这是因为必须解包 UserDefaults 才能引用成员对象。试试看

【讨论】:

Xcode 响应“不能在 'UserDefaults' 类型的非可选值上使用可选链接”并建议删除添加的“?” 那么原始版本到底有什么问题? (也许用确切的问题更新问题)。 “我需要在重新启动应用程序时恢复阵列中的数据”到底是什么意思,您是否希望它们在重新启动时出现? (“恢复”有点难以理解)。你打算在哪里使用 userDefaults ?也许你应该考虑使用suiteName。查看 Apple 文档 没关系。如果您编写 userDefaults.set(sharedData, forKey: "arrayKey") 您正在使用 sharedData 中的数据填充 userDefaults 的键“arrayKey”,但如果您刚刚启动应用程序,sharedData 是空的,所以如果您尝试,立即之后,用 let savedData: [String] = userDefaults.object(forKey: "arrayKey") 填充 savedDate 它将是空的,因为 userDefaults 中的 "arrayKey" 是空的。因此,当用户输入填充 shareData 时,您需要使用 shareData 在 userdefaults 中填充“arrayKey”,然后在应用启动时,从 userdefaults 填充 savedData(开始时的某处)。 字符不够清晰。我的意思是,您必须在不同的时刻填充 userdefaults 然后填充 savedData 否则如果您刚刚启动应用程序(A = B,B = C,所以 A = C,如果 A = 空,C = 空)。因此,找到将 sharedData 存储在 userDefaults 中的合适时机,以及使用 Userdefaults 内容填充 savedData 的合适时机。如果你有它,也许可以在启动类中做第二件事,或者在启动的场景委托中做第二件事,或者根据你的项目做其他事情。 我把它整理好了。无需套件名称:。我只需要正确处理工作流程。我试图把它复杂化太多。感谢您的帮助!【参考方案2】:

根据MrHim 的建议,我从我的第一个VC 的viewDidLoad 中删除了saveArray 和retrieveArray 函数,并将retrieveArray 留在了我的第二个VC 的viewDidLoad 中。在我的 viewDidLoads 中有 saveArray 是用空数据覆盖数组。然后我需要在我的第二个 VC 中的适当位置检索数组数据。然后在我的 numberOfRowsInSection 中,我删除了 retrieveArray。

【讨论】:

以上是关于如何使用全局变量数组实现 userDefaults的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中使用 UserDefaults 进行全局更新

PHP中如何定义全局数组?

如何使用 userDefaults 保存打印数组(swift 3)

SwiftUI:如何使用 UserDefaults 持久化 @Published 变量?

使用 UserDefaults 相互替换的值

如何解决 myModel 变量中的 UserDefaults 设置错误?