2011-11-08 13 views
10

Acabo de encontrar un problema interesante con mi aplicación. En la aplicación, guardo el nombre de usuario y la contraseña del usuario en el llavero.iOS KeychainItemWrapper no se actualiza

keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyLoginPassword" accessGroup:nil]; 

[keychainWrapper setObject:usernameField.text forKey:(id)kSecAttrAccount]; 
[keychainWrapper setObject:passwordField.text forKey:(id)kSecValueData]; 

Cuando este código se ejecuta en Debug parece funcionar bien. Se actualiza cada vez y luego puedo recuperar los elementos del llavero. Sin embargo, cuando se ejecuta en Distribución, el llavero nunca se actualiza. He verificado que sí, estas líneas de código se publican en ambas compilaciones. Estoy usando Xcode 4.2 con iOS5 SDK y ejecutando la aplicación en un iPad 2 con iOS5 instalado.

Respuesta

16

También tuve este problema, y ​​me tomó por siempre para averiguar

Hay una versión de "KeychainWrapper" flotando alrededor que lo tiene es SecItemUpdate dentro de un NSAssert (entre otras cosas).

¡Quienquiera que haya hecho esto es un imbécil !, al compilar para su lanzamiento/distribución, cada NSAssert queda anulado, lo que significa que el código ni siquiera se ejecuta.

Por ejemplo:

NSAssert(SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck), @"Couldn't update the Keychain Item."); 

necesita convertirse en

OSStatus status = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)tempCheck); 
NSAssert(status == noErr, @"Couldn't update the Keychain Item."); 

Aviso cómo el SecItemUpdate real se mueve fuera de la NSAssert, y en su lugar el resultado se comprobó

Nota importante: Intentando actualizar un valor para kSecValueData, sin especificar también un valor para kSecAttrAccount, hará que la aserción también falle. Por lo tanto, si su intención es la de almacenar una única serie de datos sensibles (tales como una lista de números de tarjetas de crédito), asegúrese de guardar un poco de texto "nombre de cuenta" en el atributo kSecAttrAccount, así:

static NSString* kCardListXML = @"cardListXML"; 
static NSString* cardListAccountName = @"cardListAccount"; 

-(void)setCardListXML:(NSString*)xml { 
    KeychainItemWrapper* wrapper = 
    [[KeychainItemWrapper alloc] initWithIdentifier:kCardListXML accessGroup:nil]; 
    [wrapper setObject:cardListAccountName forKey:(id)CFBridgingRelease(kSecAttrAccount)]; 
    [wrapper setObject:xml forKey:(id)CFBridgingRelease(kSecValueData)]; 
}  

-(NSString*)getCardListXML { 
    KeychainItemWrapper* wrapper = 
    [[KeychainItemWrapper alloc] initWithIdentifier:kCardListXML accessGroup:nil]; 
    [wrapper setObject:cardListAccountName forKey:(id)CFBridgingRelease(kSecAttrAccount)]; 
    return [wrapper objectForKey:CFBridgingRelease(kSecValueData)]; 
} 
+0

Lo había descubierto y este era esencialmente el problema. Gracias. – iHorse

+0

Parece que se corrigió en v1.2 de KeychainWrapper, disponible en el código de ejemplo de Xcode – Olaf

14

cuando se incluyen

keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyLoginPassword" accessGroup:nil]; 

[keychainWrapper setObject:usernameField.text forKey:(id)kSecAttrAccount]; 
[keychainWrapper setObject:passwordField.text forKey:(id)kSecValueData]; 

también había que incluir

[keychainWrapper setObject:@"Myappstring" forKey: (id)kSecAttrService]; 

O me sale un error "SIGABRT". (Myappstring) es una cadena que define su aplicación.

Tal vez me falta algo, esto se debe hacer al menos una vez.

+0

KeychainItemWrapper funcionaba principalmente para mí, trabajaba en muchas direcciones de correo electrónico (almacenadas como nombre de usuario en kSecAttrAccount), pero un correo electrónico en particular no funcionaba. ¡Luego agregué la línea anterior para kSecAttrService y ahora todo es perfecto! -Gracias @Andres – dbDev

+0

Luché con él por bastante tiempo. Me alegro de que ayudó –

+1

Esta solución funcionó para mí. Es complicado averiguar qué está sucediendo en los mensajes de error, porque si alguna vez has configurado estos valores correctamente, no verás un error. Solo cuando cambia el initWithIdentifier: value Y no establece kSecAttrService, entonces comienza a recibir errores. – carbocation