使用Swift查询iOS钥匙串
我坚持使用Swift转换Keychain查询结果。
我的请求似乎正在工作:
let queryAttributes = NSDictionary(objects: [kSecClassGenericPassword, "MyService", "MyAccount", true], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData]) dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { var dataTypeRef : Unmanaged<AnyObject>? let status = SecItemCopyMatching(queryAttributes, &dataTypeRef); let retrievedData : NSData = dataTypeRef!.takeRetainedValue() as NSData *** ^^^^can't compile this line^^^^ })
我的问题是,代码不会编译:
Bitcast requires both operands to be pointer or neither %114 = bitcast %objc_object* %113 to %PSs9AnyObject_, !dbg !487 Bitcast requires both operands to be pointer or neither %115 = bitcast %PSs9AnyObject_ %114 to i8*, !dbg !487 LLVM ERROR: Broken function found, compilation aborted!
我不知道如何将Unmanaged<AnyObject>
转换为NSData
。
有任何想法吗?
使用withUnsafeMutablePointer
函数和UnsafeMutablePointer
结构来检索数据,如下所示:
var result: AnyObject? var status = withUnsafeMutablePointer(&result) { SecItemCopyMatching(queryAttributes, UnsafeMutablePointer($0)) } if status == errSecSuccess { if let data = result as NSData? { if let string = NSString(data: data, encoding: NSUTF8StringEncoding) { // ... } } }
它可以很好地发布(最快的[-O])版本。
看起来像你遇到了一个编译器错误,你应该报告。 您可以采用不同的path来检索值,如下所示:
var dataTypeRef :Unmanaged<AnyObject>? let status = SecItemCopyMatching(queryAttributes, &dataTypeRef); let opaque = dataTypeRef?.toOpaque() if let op = opaque? { let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue() }
使用AnyObject
作为Unmanaged<T>
的types参数T
时,会出现错误。 下面的代码片段编译没有问题,它使用更具体的typesCFError
:
let url = NSURL(string:"dummy") var errorRef: Unmanaged<CFError>? let succeeded = CTFontManagerRegisterFontsForURL(url, .Process, &errorRef) if errorRef { let error = errorRef!.takeRetainedValue() }
由于Keychain API根据查询属性返回不同的结果,因此需要使用AnyObject
。
为了得到这个工作,你需要首先访问每个keychain常量的保留值。 例如:
let kSecClassValue = kSecClass.takeRetainedValue() as NSString let kSecAttrAccountValue = kSecAttrAccount.takeRetainedValue() as NSString let kSecValueDataValue = kSecValueData.takeRetainedValue() as NSString let kSecClassGenericPasswordValue = kSecClassGenericPassword.takeRetainedValue() as NSString let kSecAttrServiceValue = kSecAttrService.takeRetainedValue() as NSString let kSecMatchLimitValue = kSecMatchLimit.takeRetainedValue() as NSString let kSecReturnDataValue = kSecReturnData.takeRetainedValue() as NSString let kSecMatchLimitOneValue = kSecMatchLimitOne.takeRetainedValue() as NSString
然后你需要引用在Keychain字典对象中创build的常量,如下所示。
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
我写了一篇关于它的博客文章: http : //rshelby.com/2014/08/using-swift-to-save-and-query-ios-keychain-in-xcode-beta-4/
希望这可以帮助!
rshelby