2016-10-17 4 views
0

У меня есть данные, которые сохраняются с NSUserDefaults в массиве типа "[RiskEntry]".NSUserDefaults - Array пуст во втором View Controller

Позвольте мне объяснить вам, что я сохраню здесь и как процесс загрузки и сохранения выглядит в моем коде (я взял код не имеет значения, и я использую Swift3):

Main_ViewController

Первый: в классе Main_ViewController я получаю текст, переданный из popover и сохраняющий его в массиве с NSUserDefaults в riskEntry с ключом «newTry» (это просто временное имя ;-)) -> «func riskText (riskTextTransferred: String) '.

Plan_ViewController

Во-вторых, при использовании SEGUE, чтобы добраться до стола на Plan_ViewController, таблица заполнена текстом, сохраненного в riskEntry с ключом «newTry» (cell.riskTitle.text = savedTitles[indexPath.row].title as String). Пока все хорошо.

CustomCell и Plan_ViewController

В-третьих: Когда пользователь вводит значение в текстовом поле клетки (consequences.text), последствия значение обновляется для riskEntry. Итак, в начале массив имел пустую строку для последствий. Теперь запись была обновлена ​​с текстом.

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

Новая строка сохраняется с ключом «newTry». Это также работает, как и ожидалось.

Main_ViewController

Четвертое: Теперь я уволить Plan_ViewController вернуться к Main_ViewController. Когда я теперь пытаюсь загрузить мой массив в viewWillAppear() с помощью ключа «newTry», он пуст.

Что я делаю неправильно? Как я могу успешно загрузить обновленные данные из Plan_ViewController в Main_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: $0)! } 
      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 {$0.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: $0)! } 

     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: $0)! } 
      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: $0)! } 
     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: {$0.title.contains(identifier)}) { 
      savedTitle[index].consequences = consequencesTranferred 
      let encoded = riskEntry.map { $0.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") 
     } 

    } 
} 

CustomCell

// ----------- 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) 
    } 
} 
+0

В основном 'NSUserDefaults' является неправильным местом для хранения временных данных, особенно данных, передаваемых между контроллерами представлений. – vadian

+0

Мои данные не должны временно сохраняться. Данные должны быть доступны после перезапуска приложения ... – Jake2Finn

+0

Возможно, я неправильно понял ваш вопрос, но вы просто хотите передать данные с Plan_VC на Main_VC, а затем сохранить эти данные, это правильно? Если это так, вы должны использовать делегат, потому что NSUserDefaults имеет временную задержку для сохранения данных. –

ответ

0

Поскольку существует небольшая задержка по времени на NSUserDefaults, в то время вы уволить Plan_ViewController, то newTry не сохранены (потребовалось некоторое время для записи на диск, я думаю), но метод viewWillAppear() в `Main_ViewController немедленно вызывается. Таким образом, из-за задержки времени массив пуст.

Чтобы избежать этого, вы не можете устранить временную задержку, что вы можете сделать, это использовать делегат для передачи данных обратно в ваш первый VC.

Поэтому вместо того, чтобы извлекать массив из NSUserDefaults, вы должны сделать это непосредственно из вызова делегата.

+0

Нельзя задерживать при использовании' synchronize' ... при условии, что это успешно , –

+0

@PhillipMills Да, есть незаметная задержка, возможно, 2 мс. Сначала вы можете убедиться, что ваш массив правильно сохранен, распечатав его в другом месте (возможно, все еще печатайте в 'viewWillAppear', но на этот раз вы можете выйти из приложения и перезапустить его, посмотреть, печатает ли он правильные данные). Если это правда, то эта небольшая небольшая задержка влияет на ваше приложение. –

+0

Если 'synchronize' на самом деле является асинхронным (т. Е. Данные не могут быть записаны при его возврате), это будет ошибкой в ​​соответствии с его документацией. –

Смежные вопросы