能否在NSUserDefaults中持久化HKQueryAnchor?

3

所以我有点沮丧,因为苹果用一个易于处理的透明的NSUInteger替换了一个HKQueryAnchor,但没有提供一种简单的方法来持久化这个HKQueryAnchor。有人找到了使用NSUserDefaults来实现这个目的的好方法吗?我所看到的唯一的持久化方法是将其存档到本地文件中,但我的应用程序将所有东西都持久化在NSUserDefaults中,并且如果可能的话,我想保持这样的方式。有可靠的方法以这种方式存储HKQueryAnchor吗?


是的,您的类需要符合 NSCoding 协议,然后您就可以随时对其进行归档或解档。 - holex
3个回答

6
你可以使用NSKeyedArchiver将其转换为NSData并将其存储在用户默认设置中。
存储方式:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:anchor];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"AnchorData"];

获取数据的方法:

NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"AnchorData"];
HKQueryAnchor *anchor = [NSKeyedUnarchiver unarchiveObjectWithData:data];

你可能已经知道HKQueryAnchor类基本上不符合NSCoding协议... - holex
@holex 看起来它符合 NSSecureCoding 的要求。那么我是否可以像上面那样进行归档并存储在 NSUserDefaults 中,或者 NSSecureCoding 的某些特性会禁止 NSUserDefaults? - helloB
我在使用这个方法时遇到了一些一致性问题,@dan你有没有遇到过类似的情况?我的代码返回了旧的锚点或空值。我正在使用你建议的代码,在查询之前请求最新的值。 - Mahdi Yusuf

0

Swift 5

你可以将锚点声明为一个计算属性,它使用NSKeyedUnarchiver解码存储在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
    }

在你的HKAnchoredObjectQuery上,你可以使用闭包提供的NSKeyedArchiver对新的锚点进行编码,然后将其存储到你的存储值中使用NSUserDefaults
if let newEncodedAnchor = try? NSKeyedArchiver.archivedData(withRootObject: newAnchor, requiringSecureCoding: true) {
          // Store the encoded anchor data in UserDefaults
          self.myAnchor = newEncodedAnchor
      }

为什么要将requiringSecureCoding: false设置为false? - matt
好的,@matt 很棒。requireSecureCoding 最好设置为 true,因为 HKQueryObject 符合 NSSecureCoding 的要求。我会编辑答案。 - allmightu

0
这个答案是基于 @allmightu 的答案,但没有使用 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)
            }
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接