2016-10-15 18 views
1

我有問題想弄清楚如何使用NSUserDefaults保存我的「RiskEntry」類型的字符串。我已經通過其他一些帖子,但不知何故,我仍然無法解決這個問題。使用NSUserDefaults和結構類型數組

讓我來解釋一下下面的代碼吧:我在下面的代碼片段中從我的類CustomCell中獲取一些數據。在這裏,我首先檢查一個「標識符」要更新哪個數組,使用新的數組值「結果」。

它一切正常,更新後的數組存儲在riskEntry中。 但是,我現在無法解決如何使用NSUserDefaults進行存儲。當我嘗試用例如riskItemDefaults.set(riskEntry, forKey: "riskItem")我收到一個異常錯誤。

任何想法我在做什麼錯在這裏?

SWIFT3(我刪除了這個問題不相關的所有代碼)

class: RiskPlan: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomCellUpdaterDelegate { 

var riskEntry = [RiskEntry]() 
var riskItemDefaults = UserDefaults.standard 

// ------ start of delegate function (receiving from CustomCell) --------- 
     func transferData(consequencesTranferred: String, identifier: String) { 
     if let index = riskEntry.index(where: {$0.title as String == identifier}) { 
      riskEntry[index].consequences = consequencesTranferred 
    } else { 
     print ("nothing") 
    } 

// save with NSUserDefaults 
     riskItemDefaults.set(riskEntry, forKey: "riskItem") 
    } 
} 

這是我的結構:

public struct RiskEntry { 
    let title: String 
    var consequences: String 
} 

我自定單元

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

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

    var delegate: CustomCellUpdaterDelegate? 

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

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

你收到的例外是什麼? –

+0

我的控制檯輸出是:'libC++ abi.dylib:以'NSException類型的未捕獲異常終止,而我的AppDelegate.swift類被選爲'線程1:信號SIGABRT' – Jake2Finn

+1

可能的http://stackoverflow.com/重複問題/ 38406457 /如何保存一個自定義數組結構到nsuserdefault-with-swift?rq = 1 – hotpaw2

回答

1

的問題是你不能將自定義數組保存在NSUserDefaults中。要做到這一點,你應該改變他們的NSData然後將其保存在NSUserDefaults的 這是我在項目中使用它在迅速2語法,我不認爲這會是很難將其轉換爲SWIFT 3

let data = NSKeyedArchiver.archivedDataWithRootObject(yourObject); 
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "yourKey") 
NSUserDefaults.standardUserDefaults().synchronize() 
代碼

,並在獲取部分使用這種組合

if let data = NSUserDefaults.standardUserDefaults().objectForKey("yourKey") as? NSData { 
    let myItem = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? yourType 
} 

希望這將有助於

0

最接近的類型到UserDefaults支持可能是一個NSDictionary迅捷的結構。您可以在保存數據之前將結構元素複製到Objective C NSDictionary對象中。在UserDefaults

1

保存對象有非常具體的限制:

set(_:forKey:) reference:

值參數可以是唯一的財產清單對象:NSData的,的NSString,NSNumber的,NSDate的,NSArray的,或者NSDictionary的。對於NSArray和NSDictionary對象,其內容必須是屬性列表對象。

您需要序列化您的模型,使用NSCoding或作爲使用JSON的替代方法映射到UserDefaults支持的值。

0

我能夠基於@ahruss編程解決方案(How to save an array of custom struct to NSUserDefault with swift?)。不過,我將其修改爲swift 3,並且還顯示瞭如何在UITableView中實現此解決方案。我希望它能夠幫助別人的未來:

  1. 從下面的擴展添加到您的結構(它調整到你自己的變量)

  2. 保存所需的陣列項目是這樣的:

    讓編碼= riskEntry.map {$ 0.encode()} riskItemDefaults.set(編碼,forKey: 「後果」) riskItemDefaults.synchronize()

  3. 加載您的項目像這樣

    let dataArray = riskItemDefaults.object(forKey:「effects」)as! [NSData] let savedFoo = dataArray.map {RiskEntry(data:$ 0)! }

  4. 如果你想顯示保存的數組元素在你的細胞,進行這樣:

    cell.consequences.text = savedFoo [indexPath.row] .consequences作爲字符串

下面是完整的代碼,修改後用於Swift3

結構

// ---------------- structure for table row content ----------------- 
struct RiskEntry { 
    let title: String 
    var consequences: String 
} 

分機號碼

extension RiskEntry { 
     init?(data: NSData) { 
      if let coding = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? Encoding { 
       title = coding.title as String 
       consequences = (coding.consequences as String?)! 
      } else { 
       return nil 
      } 
     } 

     func encode() -> NSData { 
      return NSKeyedArchiver.archivedData(withRootObject: Encoding(self)) as NSData 
     } 

     private class Encoding: NSObject, NSCoding { 
      let title : NSString 
      let consequences : NSString? 


      init(_ RiskEntry: RiskEntry) { 
       title = RiskEntry.title as NSString 
       consequences = RiskEntry.consequences as NSString? 
      } 

      public required init?(coder aDecoder: NSCoder) { 
       if let title = aDecoder.decodeObject(forKey: "title") as? NSString { 
        self.title = title 
       } else { 
        return nil 
       } 
       consequences = aDecoder.decodeObject(forKey: "consequences") as? NSString 
      } 

      public func encode(with aCoder: NSCoder) { 
       aCoder.encode(title, forKey: "title") 
       aCoder.encode(consequences, forKey: "consequences") 
      } 

     } 
    }