是否可以在 iOS 12 上运行的类中使用 @available(iOS 13) 计算属性?



这里的答案:https://stackoverflow.com/a/51250282/1343140 说应该可以将lazy var标记为@available比运行时使用的iOS版本更高的版本。

我正在处理一些代码,如果用户使用的是iOS 13,则他们的数据将被加密(因为它存储在云中(。在iOS 12中,他们的数据存储在本地,未加密。

这是我正在做的事情的简化版本:

import CryptoKit
import Foundation
class DataStore {
@available(iOS 13.0, *)
fileprivate lazy var crypto = Crypto()
func store(data: Data) {
let url = URL(fileURLWithPath: "myfile.dat")
if #available(iOS 13.0, *) {
try! crypto.encrypt(data: data).write(to: url)
} else {
try! data.write(to: url)
}
}
}
@available(iOS 13.0, *)
class Crypto {
// SymetricKey is only available in iOS 13. In reality we may load this from keychain
lazy private var key: SymmetricKey = SymmetricKey(size: .bits256)
func encrypt(data: Data) -> Data {
// do encrpyion
return data
}
}
let store = DataStore()
store.store(data: "hello data".data(using: .utf8)!)

这编译得很好,并且在 iOS 13 中运行良好。

但是,在iOS 12中,当调用let store = DataStore()时,我在运行时看到以下崩溃:

dyld: lazy symbol binding failed: can't resolve symbol _$s9CryptoKit12SymmetricKeyVMa in [...] because dependent dylib #7 could not be loaded
dyld: can't resolve symbol _$s9CryptoKit12SymmetricKeyVMa in [...] because dependent dylib #7 could not be loaded

我希望不必在每次调用store函数时都加载Crypto类,因为有大量开销(从钥匙串读取(,但我无法弄清楚如何使Crypto成为一个属性,以便它保留在 iOS 13 的内存中,并且在 iOS 12 中根本没有加载。

这可能吗?如果没有,解决这个问题的最佳方法是什么?让加密货币成为单例?!

您需要将CryptoKit框架弱链接到您的项目。即使未执行访问CryptoKit的代码路径,您的文件中也有一个在较旧的iOS版本上执行的import语句。

弱链接可解决此问题。有关弱链接的更多信息,请参阅弱链接的官方文档。

我添加了 Dávid 推荐的弱链接,但我仍然看到同样的问题。

就我而言,我切换到了一个单例,它允许密钥保留在内存中,但意味着可以在运行时明确避免它。

import CryptoKit
import Foundation
class DataStore {
/* ❌ */
// @available(iOS 13.0, *)
// fileprivate lazy var crypto = Crypto()
func store(data: Data) {
let url = URL(fileURLWithPath: "myfile.dat")
if #available(iOS 13.0, *) {
/* ❌ */
// try! crypto.encrypt(data: data).write(to: url)
/* ✅ */
try! Crypto.shared.encrypt(data: data).write(to: url)
} else {
try! data.write(to: url)
}
}
}
@available(iOS 13.0, *)
class Crypto {
// 👇
static var shared = Crypto()
private init() {}
// 👆
// Symetric key is only available in iOS 13
lazy private var key: SymmetricKey = SymmetricKey(size: .bits256)
func encrypt(data: Data) -> Data {
// do encrpyion
return data
}
}
let store = DataStore()
store.store(data: "hello data".data(using: .utf8)!)

最新更新