我有问题要弄清楚如何保存我的字符串" 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 :(得分:1)
问题是您无法在NSUserDefaults中保存自定义数组。为此,您应该将它们更改为NSData,然后将其保存在NSUserDefaults中 这是我在我的项目中使用的代码,它采用swift 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
}
希望这会有所帮助
答案 1 :(得分:1)
保存UserDefaults
中的对象有非常具体的限制:
value参数只能是属性列表对象:NSData,NSString,NSNumber,NSDate,NSArray或NSDictionary。对于NSArray和NSDictionary对象,它们的内容必须是属性列表对象。
您需要使用NSCoding序列化模型,或者使用JSON作为替代方案,以UserDefaults
映射到支持的值。
答案 2 :(得分:0)
UserDefaults支持的Swift结构的最接近类型可能是NSDictionary。在保存数据之前,您可以将struct元素复制到Objective C NSDictionary对象中。
答案 3 :(得分:0)
我能够基于@ahruss(How to save an array of custom struct to NSUserDefault with swift?)编写解决方案。但是,我为swift 3修改了它,它还显示了如何在UITableView中实现此解决方案。我希望它可以在将来帮助某人:
将扩展名从下方添加到您的结构中(将其调整为您自己的变量)
保存所需的数组项,如下所示:
let encoded = riskEntry.map {$ 0.encode()} riskItemDefaults.set(encoded,forKey:“后果”) riskItemDefaults.synchronize()
像这样加载你的项目
让dataArray = riskItemDefaults.object(forKey:“后果”)为! [NSData的] let savedFoo = dataArray.map {RiskEntry(data:$ 0)! }
如果您想在单元格中显示已保存的数组项,请按以下方式进行操作:
cell.consequences.text = savedFoo [indexPath.row] .consequences as String
以下是针对 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")
}
}
}