使用 Swift 将类中的结构保存到 NSUserDefaults
Posted
技术标签:
【中文标题】使用 Swift 将类中的结构保存到 NSUserDefaults【英文标题】:Save struct in class to NSUserDefaults using Swift 【发布时间】:2014-08-28 10:36:47 【问题描述】:我有一个类,类内部是一个(swift)数组,基于全局结构。 我想将这个类的数组保存到 NSUserDefaults。这是我的代码:
struct mystruct
var start : NSDate = NSDate()
var stop : NSDate = NSDate()
class MyClass : NSObject
var mystructs : [mystruct]
init(mystructs : [mystruct])
self.mystructs = mystructs
super.init()
func encodeWithCoder(encoder: NSCoder)
//let val = mystructs.map $0 as NSObject //this also doesn't work
let objctvtmrec = NSMutableArray(mystructs) //gives error
encoder.encodeObject(objctvtmrec)
//first approach:
encoder.encodeObject(mystructs) //error: [mystructs] doesn't conform to protocol 'anyobject'
var records : [MyClass]
get
var returnValue : [MyClass]? = NSUserDefaults.standardUserDefaults().objectForKey("records") as? [MyClass]
if returnValue == nil
returnValue = []
return returnValue!
set (newValue)
let val = newValue.map $0 as AnyObject
NSUserDefaults.standardUserDefaults().setObject(val, forKey: "records")
NSUserDefaults.standardUserDefaults().synchronize()
我已经继承了 NSObject,并且我知道我需要 NSCoding。但我没有找到任何方法将结构数组转换为 NSMuteableArray 或我可以存储的类似内容。到目前为止,唯一的想法是遍历每个条目并将其直接复制到一个新数组中,或者在整个项目中使用大量或 Objective-c 代码,因此我永远不需要从 swift 数组转换为 Objective-c 数组。两者都是我不想做的事情。
【问题讨论】:
【参考方案1】:Swift 结构不是类,因此它们不符合AnyObject
协议。你必须重新考虑你的方法。以下是一些建议:
将您的 struct
转换为 final class
以强制执行不变性
final class MyStruct
let start : NSDate = NSDate()
let stop : NSDate = NSDate()
encoder.encodeObject(mystructs)
将它们映射为[String: NSDate]
类型的数组字典
let structDicts = mystructs.map ["start": $0.start, "stop": $0.stop]
encoder.encodeObject(structDicts)
【讨论】:
let structDicts = mystructs.map ["start": $0.start, "stop": $0.stop]
-> 致命错误:NSArray 元素无法匹配 Swift Array 元素类型【参考方案2】:
NSUserDefaults
可以处理的类型有限:NSData
、NSString
、NSNumber
、NSDate
、NSArray
、NSDictionary
和 Bool
。因此 no 可以保存 Swift 对象或结构。其他任何内容都必须转换为 NSData
对象。
NSUserDefaults
的工作方式与NSArchiver
不同。由于您已经将NSCoder
添加到您的课程中,您最好的选择可能是使用NSArchiver
保存和恢复到Documents
目录中的文件..
来自 Apple NSUserDefaults
文档:
默认对象必须是属性列表,即(或 对于集合实例的组合):NSData,NSString, NSNumber、NSDate、NSArray 或 NSDictionary。如果你想存储任何 其他类型的对象,您通常应该将其归档以创建一个 NSData 的实例。
【讨论】:
【参考方案3】:我开发了a small library,这可能会有所帮助。您可以将它用作 NSCoding
的 Swift 结构的替代品。
您需要为mystruct
实现Koting
协议:
struct mystruct: Koting
var start : NSDate = NSDate()
var stop : NSDate = NSDate()
// MARK: - Koting
init?(koter: Koter)
guard let start: NSDate = koter.dekotObject(forKey: "start"),
let stop: NSDate = koter.dekotObject(forKey: "stop") else
return nil
self.init(start: start, stop: stop)
func enkot(with koter: Koter)
koter.enkotObject(start, forKey: "start")
koter.enkotObject(stop, forKey: "stop")
从那时起,您可以轻松地将结构转换为Data
并返回:
let str = mystruct(start: NSDate(/*...*/), stop: NSDate(/*...*/))
guard let data = str.de_data else return // potentially may be nil
let restoredStr = mystruct.de_from(data: data) // if data is irrelevant, returns `nil`
最后,这是你为实现NSCoding
所做的:
class MyClass: NSObject, NSCoding
var mystructs: [mystruct]
init(mystructs: [mystruct])
self.mystructs = mystructs
super.init()
func encode(with aCoder: NSCoder)
guard let datas = mystructs.flatMap $0.de_data else return
aCoder.encode(datas, forKey: "mystructs")
required convenience init?(coder aDecoder: NSCoder)
guard let datas = aDecoder.decodeObject(forKey: "mystructs") as? [Data],
let mystructs = datas.flatMap mystruct.de_from(data: $0) else
return nil
self.init(mystructs : mystructs)
如果NSCoding
支持 Swift 结构,您将编写的代码几乎相同。
【讨论】:
【参考方案4】:我在使用 Swift 4 编码时在我的项目中使用这个:
let jsonData = """ "variable1":1234,"variable2":"someString""""
struct MyStruct:Codable
var variable1 :Int
var variable2:String
let whatever = try JSONDecoder().decode(MyStruct.self,from:jsonData)
let encoded =try JSONEncoder().encode(whatever)
UserDefaults.standart.set(encoded, forKey:"encodedData")
从 UserDefaults 中获取数据
if let data = UserDefaults.standard.object(forKey: "encodedData") as? Data
let myStruct = try JSONDecoder().decode(MyStruct.self, from: data)
print(myStruct)
【讨论】:
以上是关于使用 Swift 将类中的结构保存到 NSUserDefaults的主要内容,如果未能解决你的问题,请参考以下文章
如何将类中存在的 NSMutablearray 保存到文件中?
使用 NSUser Defaults 保存当前游戏分数(不是高分)?
JPA Hibernate 将类中的类中的字段映射到同一个表
Java错误排查无法将类中的构造器应用到给定类型 无法将类 uiauto.web.common.OperationNewLabelPageImpl中的构造器 OperationNewLabe