我正在尝试存储一个整数并使用 KeyChain 检索它。
我是这样保存的:
func SaveNumberOfImagesTaken()
{
let key = "IMAGE_TAKEN"
var taken = 10
let data = NSKeyedArchiver.archivedDataWithRootObject(taken)
let query : [String:AnyObject] = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : key,
kSecValueData as String : data
]
let status : OSStatus = SecItemAdd(query as CFDictionaryRef, nil)
}
这是我尝试检索它的方式:
func CheckIfKeyChainValueExitss() -> AnyObject? {
var key = "IMAGE_TAKEN"
let query : [String:AnyObject] = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : key,
kSecReturnData as String : kCFBooleanTrue,
kSecMatchLimit as String : kSecMatchLimitOne ]
var dataTypeRef :Unmanaged<AnyObject>?
let status: OSStatus = SecItemCopyMatching(query, &dataTypeRef)
if let op = dataTypeRef?.toOpaque() {
let data = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
if let string: AnyObject? = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? AnyObject? {
if key == "IMAGE_TAKEN"
{
return string as! String!
}
else if string == nil
{
return nil
}
}
}
return nil
}
我收到以下错误:
Could not cast value of type '__NSCFNumber' to 'NSString'
我尝试使用变量但没有成功。
Best Answer-推荐答案 strong>
我已经更新了 Eric 的 Swift 5 版本:
class KeyChain {
class func save(key: String, data: Data) -> OSStatus {
let query = [
kSecClass as String : kSecClassGenericPassword as String,
kSecAttrAccount as String : key,
kSecValueData as String : data ] as [String : Any]
SecItemDelete(query as CFDictionary)
return SecItemAdd(query as CFDictionary, nil)
}
class func load(key: String) -> Data? {
let query = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : key,
kSecReturnData as String : kCFBooleanTrue!,
kSecMatchLimit as String : kSecMatchLimitOne ] as [String : Any]
var dataTypeRef: AnyObject? = nil
let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
if status == noErr {
return dataTypeRef as! Data?
} else {
return nil
}
}
class func createUniqueID() -> String {
let uuid: CFUUID = CFUUIDCreate(nil)
let cfStr: CFString = CFUUIDCreateString(nil, uuid)
let swiftString: String = cfStr as String
return swiftString
}
}
extension Data {
init<T>(from value: T) {
var value = value
self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
func to<T>(type: T.Type) -> T {
return self.withUnsafeBytes { $0.load(as: T.self) }
}
}
我已经更新了 Eric 的 Swift 3 版本:
class KeyChain {
class func save(key: String, data: Data) -> OSStatus {
let query = [
kSecClass as String : kSecClassGenericPassword as String,
kSecAttrAccount as String : key,
kSecValueData as String : data ] as [String : Any]
SecItemDelete(query as CFDictionary)
return SecItemAdd(query as CFDictionary, nil)
}
class func load(key: String) -> Data? {
let query = [
kSecClass as String : kSecClassGenericPassword,
kSecAttrAccount as String : key,
kSecReturnData as String : kCFBooleanTrue,
kSecMatchLimit as String : kSecMatchLimitOne ] as [String : Any]
var dataTypeRef: AnyObject? = nil
let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
if status == noErr {
return dataTypeRef as! Data?
} else {
return nil
}
}
class func createUniqueID() -> String {
let uuid: CFUUID = CFUUIDCreate(nil)
let cfStr: CFString = CFUUIDCreateString(nil, uuid)
let swiftString: String = cfStr as String
return swiftString
}
}
extension Data {
init<T>(from value: T) {
var value = value
self.init(buffer: UnsafeBufferPointer(start: &value, count: 1))
}
func to<T>(type: T.Type) -> T {
return self.withUnsafeBytes { $0.pointee }
}
}
示例用法:
let int: Int = 555
let data = Data(from: int)
let status = KeyChain.save(key: "MyNumber", data: data)
print("status: ", status)
if let receivedData = KeyChain.load(key: "MyNumber") {
let result = receivedData.to(type: Int.self)
print("result: ", result)
}
关于ios - 通过 KeyChain 保存和检索值,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/50038832/
|