我正在尝试将自定义对象保存到UserDefaults,并且我使用this作为源代码。 它会立即在get部分崩溃。这是我的代码:
class Settings {
static let defaults:UserDefaults = UserDefaults.standard
///VIP object:
class VIP: NSObject, NSCoding {
let email: String
let name: String
let relation: String
init(email: String, name: String, relation: String) {
self.email = email
self.name = name
self.relation = relation
}
required init(coder decoder: NSCoder) {
self.email = decoder.decodeObject(forKey: "email") as! String
self.name = decoder.decodeObject(forKey: "name") as! String
self.relation = decoder.decodeObject(forKey: "relation") as! String
}
func encode(with coder: NSCoder) {
coder.encode(email, forKey: "email")
coder.encode(name, forKey: "name")
coder.encode(relation, forKey: "relation")
}
}
///access VIPs array with this
static var VIPs: [Settings.VIP] {
get {
////CRASH (vips is not nil, and some amount of bytes)
if let vips = self.defaults.data(forKey: "VIPs"), let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: vips) as? [Settings.VIP] {
myPeopleList.forEach({print($0.email)})
return myPeopleList
} else {
return []
}
}
set {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: newValue)
self.defaults.set(encodedData, forKey: "VIPs")
}
}
}
不确定我是否遗漏了某些内容,字符串保存和检索成功,但不是这个自定义对象。
稍微重写这样的get方法:
get {
if let vips = self.defaults.data(forKey: "VIPs"){
print("counting: ", vips.count)
if let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: vips) as? [Settings.VIP]{
myPeopleList.forEach({print($0.email)})
}
}
帮助我理解它在NSKeyedUnarchiver.unarchiveObject()
部分崩溃了。但原因尚不清楚。
记录错误:
Date/Time: 2017-09-12 21:00:43.4970 +0200
Launch Time: 2017-09-12 21:00:43.1623 +0200
OS Version: iPhone OS 10.3.3 (14G5037b)
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 2
Application Specific Information:
abort() called
Filtered syslog:
None found
Last Exception Backtrace:
0 CoreFoundation 0x18f0c6fe0 __exceptionPreprocess + 124
1 libobjc.A.dylib 0x18db28538 objc_exception_throw + 56
2 Foundation 0x18fb4ab0c -[NSCoder(Exceptions) __failWithException:] + 132
3 Foundation 0x18fb4acc0 -[NSCoder(Exceptions) __failWithExceptionName:errorCode:format:] + 436
4 Foundation 0x18fb16dac _decodeObjectBinary + 408
5 Foundation 0x18fb1df10 -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:] + 1544
6 Foundation 0x18fab384c -[NSArray(NSArray) initWithCoder:] + 216
7 Foundation 0x18fb17430 _decodeObjectBinary + 2076
8 Foundation 0x18fb16b68 _decodeObject + 308
9 Foundation 0x18fb15d94 +[NSKeyedUnarchiver unarchiveObjectWithData:] + 88
10 Prep 0x100097274 0x100014000 + 537204
11 Prep 0x100078384 0x100014000 + 410500
12 Prep 0x100078bd8 0x100014000 + 412632
13 Prep 0x1000a4370 0x100014000 + 590704
14 Prep 0x1001084ac 0x100014000 + 1000620
15 Prep 0x10010b180 0x100014000 + 1012096
16 Prep 0x100044d28 0x100014000 + 199976
17 TCC 0x1912d92f8 __TCCAccessRequest_block_invoke.73 + 492
18 TCC 0x1912dc3d4 __tccd_send_block_invoke + 340
19 libxpc.dylib 0x18e1baf30 _xpc_connection_reply_callout + 80
20 libxpc.dylib 0x18e1baea0 _xpc_connection_call_reply + 40
21 libdispatch.dylib 0x18df7e9a0 _dispatch_client_callout + 16
22 libdispatch.dylib 0x18df8d0d4 _dispatch_queue_override_invoke + 644
23 libdispatch.dylib 0x18df8ea50 _dispatch_root_queue_drain + 540
24 libdispatch.dylib 0x18df8e7d0 _dispatch_worker_thread3 + 124
25 libsystem_pthread.dylib 0x18e187100 _pthread_wqthread + 1096
26 libsystem_pthread.dylib 0x18e186cac start_wqthread + 4
更新
它仅在第二次运行时从xcode发生,所以第一次运行 - 它工作,并尝试再次运行 - 与所描述的输出崩溃。那么存在对象一定有什么东西吗?
答案 0 :(得分:1)
根据https://stackoverflow.com/a/4197319/4601900 问题是不允许将自定义类存储为Settings plist(NSUserDefaults)中的节点,因为数据存储在文件系统中而不是应用程序中的对象。设置应用程序(此数据也将可见)不知道什么是" VIP"对象是。
我遇到了同样的问题,我设法解决了这个问题,将数据保存在文件中并从保存位置获取
我按照键
动态存储2-3个值我创建了对我有用的通用函数。
let LocalServiceCacheDownloadDir = "LocalData"
// Put your keys here
enum WSCacheKeys:String {
case Key1 = "Test1"
case Key2 = "Test2"
case Key3 = "Test3"
}
func getBaseForCacheLocal(with fileName:String) -> String? {
let filePath = FileManager.default.getDocumentPath(forItemName: self.LocalServiceCacheDownloadDir)
if FileManager.default.directoryExists(atPath: filePath) {
return filePath.stringByAppendingPathComponent(fileName)
} else {
if FileManager.default.createDirectory(withFolderName: self.LocalServiceCacheDownloadDir) {
return filePath.stringByAppendingPathComponent(fileName)
}
}
return nil
}
//------------------------------------------------------------
func cacheDataToLocal<T>(with Object:T,to key:WSCacheKeys) -> Bool {
let success = NSKeyedArchiver.archiveRootObject(Object, toFile: getBaseForCacheLocal(with: key.rawValue)!)
if success {
Logger.success(s: "Local Data Cached\(String(describing: getBaseForCacheLocal(with: key.rawValue)))" as AnyObject)
} else {
Logger.error(s: "Sorry Failed")
}
return success
}
//------------------------------------------------------------
func loadCachedDataFromLocal<T>(with key:WSCacheKeys ) -> [T]? {
return NSKeyedUnarchiver.unarchiveObject(withFile: getBaseForCacheLocal(with: key.rawValue)!) as? [T]
}
//------------------------------------------------------------
您可以获取
等数据 let objects:[VIP]? = DataManager.sharedManager.loadCachedDataFromLocal(with: .Key1)
响应来自webservice时如何保存
self.cacheDataToLocal(with: response.result.value!, to: .Key1)
希望它对你有所帮助
答案 1 :(得分:0)
我在Swift Playground上本地尝试过,效果很好。什么都没有崩溃。但Xcode建议我在VIP类名之前添加@objc。请确保我们正确地将值设置为VIP变量。
class Settings {
static let defaults:UserDefaults = UserDefaults.standard
///VIP object:
@objc(_TtCC10Playground8Settings3VIP)class VIP: NSObject, NSCoding {
let email: String
let name: String
let relation: String
init(email: String, name: String, relation: String) {
self.email = email
self.name = name
self.relation = relation
}
required init(coder decoder: NSCoder) {
self.email = decoder.decodeObject(forKey: "email") as! String
self.name = decoder.decodeObject(forKey: "name") as! String
self.relation = decoder.decodeObject(forKey: "relation") as! String
}
func encode(with coder: NSCoder) {
coder.encode(email, forKey: "email")
coder.encode(name, forKey: "name")
coder.encode(relation, forKey: "relation")
}
}
///access VIPs array with this
static var VIPs: [Settings.VIP] {
get {
////CRASH (vips is not nil, and some amount of bytes)
if let vips = self.defaults.data(forKey: "VIPs"), let myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: vips) as? [Settings.VIP] {
myPeopleList.forEach({print($0.email)})
return myPeopleList
} else {
return []
}
}
set {
let encodedData = NSKeyedArchiver.archivedData(withRootObject: newValue)
self.defaults.set(encodedData, forKey: "VIPs")
}
}
}
let vip = Settings.VIP.init(email: "dev.rnarendra@gmail.com", name: "naren", relation: "cool")
Settings.VIPs = [vip]
_ = Settings.VIPs
答案 2 :(得分:0)