2016-10-17 12 views
0

"[RiskEntry]"タイプの配列にNSUserDefaultsとともに保存されたデータがあります。NSUserDefaults - 2番目のView Controllerで配列が空です

Main_ViewController

を:

私はここに保存し、読み込みと保存のプロセスは私のコードでどのように見えるか(私は関係のないと私はSwift3を使用していたコードを取り出して)何をあなたに説明しましょう

First:クラスMain_ViewControllerで、私はポップオーバーから転送されたテキストを取得し、NSUserDefaultsをriskEntryにキー "newTry"で保存します(これは一時的な名前です;-)) - > 'func riskText riskTextTransferred:String) 'を返します。

Plan_ViewController

第二:Plan_ViewController上の表を取得するセグエを使用して、テーブルがキー「newTry」(cell.riskTitle.text = savedTitles[indexPath.row].title as String)とriskEntryに保存されたテキストで満たされています。これはこれまですべて正常に動作します。ユーザーがセル(consequences.text)のテキストフィールドに値を入力すると、値の結果はriskEntryのために更新されています

サード

CustomCellPlan_ViewController。だから最初は配列には結果のための空文字列がありました。今、エントリはテキストで更新されました。

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

新しい文字列は、キー "newTry"で保存されます。これは期待どおりに機能します。

Main_ViewController

第四:今、私は戻ってMain_ViewControllerに行くにPlan_ViewControllerを解任。 viewWillAppear()でキー "newTry"でArrayをロードしようとすると、空になります。

私は間違っていますか? 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: $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は、一時的なデータ、特にView Controller間で渡されるデータを保存する場所が間違っています。 – vadian

+0

私のデータは一時的に保存されることは想定されていません。アプリケーションを再起動してもデータは使用可能になるはずです... – Jake2Finn

+0

質問に誤解を招くかもしれませんが、Plan_VCからMain_VCにデータを渡して、このデータを保存したいのですが、それは正しいですか?その場合、NSUserDefaultsにデータを保存するための時間遅延があるため、デリゲートを使用する必要があります。 –

答えて

0

NSUserDefaults上の小さな時間遅れがあるので、あなたがPlan_ViewControllerを閉じる時に、newTryではありませんまだ保存されていない(時間がかかったディスクに書き込むと思います)、 `Main_ViewControllerのviewWillAppear()メソッドが直ちに呼び出されます。したがって、時間遅延のために、アレイは空である。

これを回避するには、時間の遅延を排除することはできません。デリゲートを使用して最初のVCにデータを戻すことができます。

したがって、NSUserDefaultsから配列を取得する代わりに、代理人呼び出しから直接行う必要があります。

+0

'synchronize'を使用しているときに遅延があってはなりません...成功したとします。 –

+0

@PhillipMillsはい、目に見えない遅延があります。おそらく2msです。最初に配列を適切に保存することを確認することができます( 'viewWillAppear'でも印刷できますが、今回はアプリを終了して再起動し、正しいデータが印刷されるかどうか確認してください)。真の場合、小さな小さな遅延があなたのアプリに影響を与えています。 –

+0

'synchronize'が実際には非同期である場合(つまり、データが返されたときにデータが書き込まれない場合があります)、そのドキュメントによればバグです。 –

関連する問題