The answer here: https://stackoverflow.com/a/51250282/1343140 says that it should be possible to have a lazy var
be marked @available
to higher a iOS version than used at runtime.
I am working on some code where if the user is on iOS 13 their data is encrypted (because it's stored in the cloud). In iOS 12 their data is stored locally and not encrypted.
Here is a simplified version of what I am doing:
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)!)
This compiles fine, and works well in iOS 13.
However, in iOS 12 I see the following crash at runtime when let store = DataStore()
is called:
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
I would like not to have to load the Crypto
class every time the store
function is called, because there is significant overhead (reading from keychain), but I can't figure out how to make Crypto
a property so it stays in memory for iOS 13 AND is not loaded at all in iOS 12.
Is this possible? If not, what would be the best way to approach this? Make Crypto a singleton?!