secItemCopyMatching возвращает нулевые данные
Прежде всего, я наблюдал за сессией WWDC 2013 по защите секретов с помощью цепочки для ключей. Я хочу сделать основной магазин паролей. Посмотрел все видео, но нашел то, что мне было нужно в первые 10 минут видео. Это кажется простым, но я не совсем понимаю, как работает кодирование и поиск данных.
ПРОБЛЕМА: после secItemCopyMatching я проверяю свой объект NSData, чтобы убедиться, что он не равен нулю, прежде чем преобразовать его в строку NSString. Проблема в том, что это всегда ноль. Ниже описано, как я сохраняю запись или обновление цепочки для ключей, а затем - как я ее получаю. Любая помощь и объяснения будут очень признательны.
ОБНОВЛЕНИЕ (отредактировано): Фрути Гик, спасибо за ответ. Я обновил мой код ниже, используя __bridge. Теперь моя проблема сводится к тому, правильно ли я храню и получаю пароль? Я ошибся или просто один или другой? Мой экземпляр NSData всегда равен нулю. Я проверяю коды возврата, и мои SecItemAdd и SecItemUpdate (когда существует запись привязки ключей) работают правильно. Я не могу получить строковое значение сохраненных данных (код доступа), чтобы сравнить его с паролем, введенным пользователем. Ценю помощь, ребята и девочки. Вот что я делаю сейчас:
ОБНОВЛЕНИЕ № 2: (Отредактировано с ответами и окончательной рабочей версией Fruity Geek. Мои изменения включают только изменения в коде ниже.)
Установить запись цепочки для ключей:
NSData *secret = [_backupPassword dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: twServiceName,
(__bridge id)kSecAttrAccount: twAccountName,
(__bridge id)kSecValueData: secret,
};
OSStatus status =
SecItemAdd((__bridge CFDictionaryRef)query, NULL);
if (status == errSecDuplicateItem) {
// this item exists in the keychain already, update it
query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: twServiceName,
(__bridge id)kSecAttrAccount: twAccountName,
};
NSDictionary *changes = @{
(__bridge id)kSecValueData: secret,
};
status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)changes);
}
Восстановить пароль из цепочки для ключей:
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: twServiceName,
(__bridge id)kSecAttrAccount: twAccountName,
(__bridge id)kSecReturnData: @YES,
};
NSData *data = NULL;
CFTypeRef dataTypeRef = (__bridge CFTypeRef)data;
OSStatus status =
SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef);
NSData *data = (__bridge NSData *)dataTypeRef;
NSString *passcode = @"none";
if (status == errSecSuccess) {
// we found a keychain entry, set the passcode
if (data)
passcode = [NSString stringWithUTF8String:[data bytes]];
}
twServiceName и twAccountName являются статическими NSStrings.
Как я уже сказал, я не совсем то, что я делаю с __bridge или CFTypeRef. Я просмотрел документы по яблокам, многочисленные посты здесь и другие сайты, но цепочка для ключей и эти условия совершенно новые для меня, и я все еще пытаюсь понять это. Надеюсь, что кто-то здесь может указать на мою ошибку и помочь мне понять. Заранее спасибо за помощь.
iOS 7 / Xcode 5