Книга: iOS. Приемы программирования
Обсуждение
Обсуждение
Допустим, вы выполнили все указания, изложенные в разделе 8.2, и сохранили в связке ключей приложения строку Steve Jobs с ключом Full Name. Теперь вы хотите обновить это значение. Первым делом понадобится определить, присутствует ли уже нужное значение в связке ключей. Для этого создадим простой запрос, который вы уже видели ранее в этой главе:
NSString *keyToSearchFor = @"Full Name";
NSString *service = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: service,
(__bridge id)kSecAttrAccount: keyToSearchFor,
};
Затем сделаем запрос к этому словарю и проверим, находится ли интересующий нас элемент в связке ключей:
OSStatus found = SecItemCopyMatching((__bridge CFDictionaryRef)query,
NULL);
Можно и не проверять наличие значения перед тем, как его обновлять. Вполне допустимо просто попытаться обновить значение. Если же его не существует, функция SecItemUpdate вернет значение errSecItemNotFound. Выбор заключается в том, проводить ли поиск в связке ключей самостоятельно или перепоручить эту задачу SecItemUpdate.
Если эта функция вернет значение errSecSuccess, вы будете знать, что интересовавшее вас значение уже обновлено. Обратите внимание: в качестве второго параметра мы передали NULL. Дело в том, что мы не собираемся получать из связки ключей старое значение. Мы просто хотим определить, существует ли значение, а сделать это можем, только проверив возвращаемое значение функции. Если возвращаемое значение равно errSecSuccess, делаем вывод, что значение уже было сохранено и может быть обновлено. Обновлять значение мы будем вот так:
NSData *newData = [@"Mark Tremonti"
dataUsingEncoding: NSUTF8StringEncoding];
NSDictionary *update = @{
(__bridge id)kSecValueData: newData,
};
OSStatus updated = SecItemUpdate((__bridge CFDictionaryRef)query,
(__bridge CFDictionaryRef)update);
if (updated == errSecSuccess){
NSLog(@"Successfully updated the existing value");
} else {
NSLog(@"Failed to update the value. Error = %ld", (long)updated);
}
Обновляющий словарь, который мы передаем функции SecItemUpdate в качестве второго параметра, может содержать больше ключей чем один ключ kSecValueData, использованный в нашем примере. На самом деле этот словарь может содержать обновления для любого имеющегося элемента. Например, если вы хотите добавить комментарий к имеющемуся значению (комментарий — это строка), то можете выполнить обновление следующим образом:
#import «AppDelegate.h»
#import <Security/Security.h>
@implementation AppDelegate
— (void) readExistingValue{
NSString *keyToSearchFor = @"Full Name";
NSString *service = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: service,
(__bridge id)kSecAttrAccount: keyToSearchFor,
(__bridge id)kSecReturnAttributes: (__bridge id)kCFBooleanTrue,
};
CFDictionaryRef cfAttributes = NULL;
OSStatus found = SecItemCopyMatching((__bridge CFDictionaryRef)query,
(CFTypeRef *)&cfAttributes);
if (found == errSecSuccess){
NSDictionary *attributes =
(__bridge_transfer NSDictionary *)cfAttributes;
NSString *comments = attributes[(__bridge id)kSecAttrComment];
NSLog(@"Comments = %@", comments);
} else {
NSLog(@"Error happened with code: %ld", (long)found);
}
}
— (BOOL) application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
NSString *keyToSearchFor = @"Full Name";
NSString *service = [[NSBundle mainBundle] bundleIdentifier];
NSDictionary *query = @{
(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrService: service,
(__bridge id)kSecAttrAccount: keyToSearchFor,
};
OSStatus found = SecItemCopyMatching((__bridge CFDictionaryRef)query,
NULL);
if (found == errSecSuccess){
NSData *newData = [@"Mark Tremonti"
dataUsingEncoding: NSUTF8StringEncoding];
NSDictionary *update = @{
(__bridge id)kSecValueData: newData,
(__bridge id)kSecAttrComment: @"My Comments",
};
OSStatus updated = SecItemUpdate((__bridge CFDictionaryRef)query,
(__bridge CFDictionaryRef)update);
if (updated == errSecSuccess){
[self readExistingValue];
} else {
NSLog(@"Failed to update the value. Error = %ld", (long)updated);
}
} else {
NSLog(@"Error happened with code: %ld", (long)found);
}
self.window = [[UIWindow alloc]
initWithFrame: [[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
В этом примере важнее всего отметить, что мы включили в обновляющий словарь ключ kSecAttrComment. Как только обновление будет выполнено, мы считаем комментарий с помощью того самого метода считывания, который изучили в разделе 8.3.