NSUserDefaults - 第二个视图控制器中的数组为空

NSUserDefaults - Array is empty in second View Controller

我有使用 NSUserDefaults 保存在类型为“[RiskEntry]”的数组中的数据。

让我向您解释一下我在这里保存的内容以及加载和保存过程在我的代码中的样子(我删除了不相关的代码,我正在使用 Swift3) :

Main_ViewController

首先:在 class Main_ViewController 中,我从弹出窗口中获取文本并将其保存在一个数组中,NSUserDefaults 位于 riskEntry 中,键为 "newTry"(这只是一个临时名称 ;-)) -> 'func riskText(riskTextTransferred: String)'.

Plan_ViewController

其次:当使用 segue 到达 Plan_ViewController 上的 table 时,table 填充了保存在 riskEntry 中的文本,键为 "newTry"( cell.riskTitle.text = savedTitles[indexPath.row].title as String)。到目前为止一切正常。

CustomCellPlan_ViewController

第三:当用户在单元格的文本字段中输入值时 (consequences.text),将更新 riskEntry 的值结果。所以一开始,数组的结果是一个空字符串。现在,条目已更新为文本。

if let index = savedTitle.index(where: {[=10=].title.contains(identifier)}) {
            savedTitle[index].consequences = consequencesTranferred

然后使用密钥 "newTry" 保存新字符串。这也像预期的那样工作。

Main_ViewController

第四:现在我驳回Plan_ViewController回到Main_ViewController。当我现在尝试使用键 "newTry" 在 vi​​ewWillAppear() 中加载我的数组时,它是空的。

我做错了什么?如何在 Main_ViewController 中成功加载 Plan_ViewController 的更新数据?

Main_ViewController

class Main_ViewController: UIViewController, UIPopoverPresentationControllerDelegate, UIGestureRecognizerDelegate {
    var riskItemDefaults = UserDefaults.standard
    var riskEntry = [RiskEntry]()

    override func viewWillAppear(_ animated: Bool) {

        if let dataArrayTitle = riskItemDefaults.object(forKey: "newTry") as? [NSData] {  
            var savedTitle = dataArrayTitle.map { RiskEntry(data: [=11=])! }
            riskItemDefaults.synchronize()

            // CHECKPOINT: all arrays are printed empty...
            print ("savedTitle: ")
            print (savedTitle)
            print ("dataArrayTitle: ")
            print (dataArrayTitle)
        } else {
           print ("nothing")
        }
    }


    // ---------------- delegate function that creates the array items -----------------
    func riskText(riskTextTransferred: String) {

        // CHECKPOINT: Array is saved correctly
        riskEntry = [RiskEntry(title: riskTextTransferred, consequences: "")]
        let encoded = riskEntry.map {[=11=].encode() }
        riskItemDefaults.set(encoded, forKey: "newTry")
        riskItemDefaults.synchronize()
    }
}

Plan_ViewController

class Plan_VC: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomCellUpdaterDelegate  {
    @IBOutlet weak var tableView: UITableView!
    var riskEntry = [RiskEntry]()
    var riskItemDefaults = UserDefaults.standard

    // ---------------- table settings -----------------
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        // load saved data and count number of entries for numberOfSections
        let dataArrayTitles = riskItemDefaults.object(forKey: "newTry") as! [NSData]
        let savedTitles = dataArrayTitles.map { RiskEntry(data: [=12=])! }

        return savedTitles.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = self.tableView!.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CellCustomized
        cell.delegate = self

            // load saved data and insert title in cell label
            let dataArrayTitles = riskItemDefaults.object(forKey: "newTry") as! [NSData]
            let savedTitles = dataArrayTitles.map { RiskEntry(data: [=12=])! }
            cell.riskTitle.text = savedTitles[indexPath.row].title as String

        return cell
    }

    // ---------------- delegate function from CustomCell -----------------
    func transferData(consequencesTranferred: String, identifier: String) {

        /// load entry
        let dataArrayTitle = riskItemDefaults.object(forKey: "newTry") as! [NSData]
        var savedTitle = dataArrayTitle.map { RiskEntry(data: [=12=])! }
        riskItemDefaults.synchronize()

        // CHECKPOINT: The entry is loaded correctly
        print("loaded: ")
        print(savedTitle)

        /// filter entry for title contains identifier and update the empty string for consequences
        if let index = savedTitle.index(where: {[=12=].title.contains(identifier)}) {
            savedTitle[index].consequences = consequencesTranferred
            let encoded = riskEntry.map { [=12=].encode() }
            riskItemDefaults.set(encoded, forKey: "newTry")
            riskItemDefaults.synchronize()

            // CHECKPOINT: The entry is updated correctly
            print("After updating for consequences: ")
            print(savedTitle)
        }else {
            print ("No title with value identifier to be filtered")
        }

    }
}

自定义单元格

// ----------- delegate to transfer entered data to VC ------------
protocol CustomCellUpdaterDelegate {
    func transferData(consequencesTranferred: String, identifier: String)
}

// ---------------- start of calss CellCustomized -----------------
class CustomCell: UITableViewCell, UIPickerViewDataSource, UIPickerViewDelegate, UITextViewDelegate {

    var myColorsClass = myColors()
    var myStylesClass = myStyles()

    var delegate: CustomCellUpdaterDelegate?

    // text fields, text views and picker views
    @IBOutlet weak var riskTitle: UITextView!
    @IBOutlet weak var consequences: UITextView!

    var nameIdentifier = String()
    var textConsequences = String()


    override func awakeFromNib() {
        super.awakeFromNib()

        // initiate textView delegate
        consequences.delegate = self    

    } // nib end


    // ---------------- listener for text view to save input in string when editing is finished -----------------
    func textViewDidEndEditing(_ textView: UITextView) {
            textConsequences = consequences.text
            nameIdentifier = riskTitle.text
            delegate?.transferData(consequencesTranferred: self.textConsequences, identifier: nameIdentifier)
    }
}

因为 NSUserDefaults 有一个小的时间延迟,当你关闭 Plan_ViewController 时,newTry 还没有保存(需要一些时间写入我认为是磁盘),但是 Main_ViewController 中的 viewWillAppear() 方法会立即被调用。因此,由于时间延迟,数组为空。

要避免这种情况,您无法消除时间延迟,您可以做的是使用委托将数据传回您的第一个 VC。

因此,与其从 NSUserDefaults 中检索数组,不如直接从委托调用中执行此操作。