ios - llavero - ver contraseña de correo en iphone
Consulta de llavero iOS usando Swift (3)
Estoy atascado convirtiendo el resultado de la consulta de Keychain usando Swift.
Mi solicitud parece estar funcionando:
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^^^^
})
Mi problema es que el código no se compilará:
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!
No sé cómo convertir Unmanaged<AnyObject>
a NSData
.
¿Algunas ideas?
Parece que ha pulsado un error del compilador, que debe informar. Puede tomar una ruta diferente para recuperar el valor, como la siguiente:
var dataTypeRef :Unmanaged<AnyObject>?
let status = SecItemCopyMatching(queryAttributes, &dataTypeRef);
let opaque = dataTypeRef?.toOpaque()
if let op = opaque? {
let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
}
El error se manifiesta cuando se utiliza AnyObject
como un parámetro de tipo T
de Unmanaged<T>
. El siguiente fragmento de código se compila sin problemas, que utiliza un tipo más específico, CFError
:
let url = NSURL(string:"dummy")
var errorRef: Unmanaged<CFError>?
let succeeded = CTFontManagerRegisterFontsForURL(url, .Process, &errorRef)
if errorRef {
let error = errorRef!.takeRetainedValue()
}
Como la API de Keychain arroja un resultado diferente según los atributos de la consulta, se requiere el uso de AnyObject
.
Para que esto funcione, primero debe acceder al valor retenido de cada constante de llavero. Por ejemplo:
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
Luego tendrá que hacer referencia a la constante que creó en el objeto del diccionario de llavero.
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])
Escribí una publicación en el blog sobre esto en: http://rshelby.com/2014/08/using-swift-to-save-and-query-ios-keychain-in-xcode-beta-4/
¡Espero que esto ayude!
rshelby
Use withUnsafeMutablePointer
function y UnsafeMutablePointer
struct para recuperar los datos, como los siguientes:
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) {
// ...
}
}
}
funciona bien con la versión de lanzamiento (Fastest [-O]).