So I'm a bit dismayed that Apple has replaced a transparent, easy-to-handle NSUInteger
with an HKQueryAnchor
but has not provided an easy way to persist that HKQueryAnchor
. Has anyone found a good way to do this with NSUserDefaults
? The only persistence method I have seen is an archiver to a local file, but my app persists everything in NSUserDefaults
, and I'd like to keep it that way if possible. Is there a reliable way to store an HKQueryAnchor
this way?
因此,苹果用HKQueryAnchor替换了透明、易于处理的NSUInteger,但没有提供一种简单的方法来保持HKQueryAnchor,这让我有点失望。有没有人找到了使用NSUserDefaults的好方法?我见过的唯一的持久化方法是本地文件的存档程序,但我的应用程序在NSUserDefaults中持久化所有内容,如果可能的话,我想保持这种方式。这样存储HKQueryAnchor有没有可靠的方法?
更多回答
yes, your class needs to conform NSCoding
protocol then you can archive or unarchive it anytime.
是的,你的类需要符合NSCoding协议,然后你可以随时存档或取消存档。
You can convert it to NSData
using NSKeyedArchiver
and store that in the user defaults.
您可以使用NSKeyedArchiver将其转换为NSData,并将其存储在用户默认设置中。
To store:
要存储:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:anchor];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"AnchorData"];
To retrieve:
要检索,请执行以下操作:
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"AnchorData"];
HKQueryAnchor *anchor = [NSKeyedUnarchiver unarchiveObjectWithData:data];
Swift 5
You can declare the anchor as a computed variable which decodes the Data that you store in NSUserDefaults
using NSKeyedUnarchiver
您可以将锚点声明为计算变量,该变量使用NSKeyedUnasiver对存储在NSUserDefaults中的数据进行解码
@AppStorage("anchorKey") private var encodedAnchor: Data?
private var myAnchor: HKQueryAnchor? {
if let encodedAnchor {
// Decode the data to get HKQueryAnchor
if let decodedAnchor = try? NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: encodedAnchor){
return decodedAnchor
}
}
return nil
}
On your HKAnchoredObjectQuery
, you can then encode the newAnchor which the closure provides using NSKeyedArchiver
which stores it to your stored value using NSUserDefaults
在HKAnchoredObtQuery上,然后可以使用NSKeyedArchiver对闭包提供的新Anchor进行编码,后者使用NSUserDefaults将其存储到您的存储值中
if let newEncodedAnchor = try? NSKeyedArchiver.archivedData(withRootObject: newAnchor, requiringSecureCoding: true) {
// Store the encoded anchor data in UserDefaults
self.myAnchor = newEncodedAnchor
}
This answer is building off @allmightu 's answer, but without the SwiftUI @AppStorage
requirement. I also packaged it into a nice get/set syntax, so this is pretty much invisible to any consumer of the variable.
这个答案是在@allmightu的S答案的基础上构建的,但没有SwiftUI@AppStorage要求。我还将它打包到一个很好的Get/Set语法中,所以对于该变量的任何使用者来说,这几乎是不可见的。
let anchorKey = "defaults-anchor-key"
var anchor: HKQueryAnchor? {
get {
guard let anchorData = UserDefaults.standard.data(forKey: anchorKey) else {
return nil
}
return try? NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: anchorData)
}
set {
guard let newValue = newValue else {
UserDefaults.standard.set(nil, forKey: anchorKey)
return
}
if let anchorData = try? NSKeyedArchiver.archivedData(withRootObject: newValue, requiringSecureCoding: true) {
UserDefaults.standard.set(anchorData, forKey: anchorKey)
}
}
}
更多回答
probably you are aware of the HKQueryAnchor
class basically does not conform the NSCoding
protocol...
您可能知道HKQueryAnchor类基本上不符合NSCoding协议……
@holex so it seems to conform to NSSecureCoding. so can I actually archive as above and store in NSUserDefaults or does something about NSSecureCoding prohibit NSUserDefaults?
@holex,因此它似乎符合NSSecureCoding。那么,我真的可以像上面那样存档并存储在NSUserDefaults中吗?或者NSSecureCoding是否禁止NSUserDefaults?
I am running into consistency issues with this method @dan have you seen anything like this? I am having things return old anchor or nil values. I am using the code you suggested and before query fires i ask for most recent value.
我用这种方法遇到了一致性问题。“丹,你见过这样的东西吗?”我让东西返回旧锚或零值。我使用的是您建议的代码,在触发查询之前,我请求最新的值。
我是一名优秀的程序员,十分优秀!