将NSUserDefaults与struct类型的数组一起使用
我有问题要弄清楚如何使用NSUserDefaults保存我的“RiskEntry”类型的字符串。 我已经完成了其他一些post,但不知怎的,我仍然无法解决这个问题。
让我解释一下下面的代码现在做了什么:我在以下代码片段中从我的类CustomCell获取了一些数据。 在这里,我首先检查一个“标识符”,使用新的数组值“后果”更新哪个数组。
一切正常,更新的数组存储在riskEntry中。 但是,我现在无法解决如何使用NSUserDefaults存储它。 当我尝试使用例如riskItemDefaults.set(riskEntry, forKey: "riskItem")
我收到exception错误。
知道我在这里做错了吗?
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") } } }
问题是您无法在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 }
希望这会有所帮助
在UserDefaults
保存对象有非常具体的限制:
set(_:forKey :)参考:
value参数只能是属性列表对象:NSData,NSString,NSNumber,NSDate,NSArray或NSDictionary。 对于NSArray和NSDictionary对象,其内容必须是属性列表对象。
您需要使用NSCoding或使用JSON替代序列化模型,以映射到UserDefaults
支持的值。
与UserDefaults支持的Swift结构最接近的类型可能是NSDictionary。 在保存数据之前,您可以将struct元素复制到Objective C NSDictionary对象中。
我能够编写一个基于@ahruss的解决方案( 如何使用swift将一组自定义结构保存到NSUserDefault? )。 但是,我为swift 3修改了它,它还显示了如何在UITableView中实现此解决方案。 我希望它可以在将来帮助某人:
-
将扩展名从下面添加到您的结构中(将其调整为您自己的变量)
-
保存所需的数组项,如下所示:
let encoded = riskEntry.map {$ 0.encode()} riskItemDefaults.set(encoded,forKey:“outcome”)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") } } }
- iOS的ScrollView需要约束的位置或高度
- 我如何访问iPhone上的SQLite数据库实例?
- 如何使用callkit获取来电号码
- XCODE:如何从设备获取/validationACCURATE时间戳
- 将UICollectionView touch事件传递给它的父UITableViewCell
- 更改字体大小以完全适合按钮内的文本?
- ios应用内订阅 – original_transaction_id何时更改?
- codesign_allocate:错误:无法find实用程序“codesign_allocate”,而不是开发人员工具或PATH
- 为什么Xcode 4不会对我的UITableViewDataSource协议的不完整实现提出警告?