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

Ответы на вопрос(1)

Ваш ответ на вопрос