- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания iOS. Приемы программирования - Вандад Нахавандипур
Шрифт:
Интервал:
Закладка:
См. также
Раздел 8.1.
8.3. Нахождение значений в связке ключей
Постановка задачи
Требуется найти в связке ключей имеющийся там элемент.
Решение
Воспользуйтесь функцией SecItemCopyMatching. Выполните следующие шаги.
1. Создайте словарь для передачи вышеупомянутой функции. Добавьте к словарю ключ kSecClass. Присвойте ключу такое значение, чтобы он отражал тип искомого элемента. Как правило, здесь требуется значение kSecClassGenericPassword.
2. Добавьте в словарь ключ kSecAttrService. В качестве значения этого ключа установите сервисную строку того элемента, который вы ищете. В этой главе в качестве имен сервисов мы используем идентификатор пакета нашего приложения и устанавливаем в качестве идентификаторов пакета всех приложений одну и ту же строку. Таким образом, одно приложение может считывать связку ключей, другое — записывать в нее данные и т. д.
3. Добавьте в словарь ключ kSecAttrAccount и задайте в качестве его значения текущий ключ того значения, которое вы ранее сохранили в связке ключей. Если вы внимательно проработали пример из раздела 8.2, то в данном случае именем учетной записи будет служить строка Full Name.
4. Добавьте к словарю атрибут kSecReturnAttributes. В качестве его значения задайте kCFBooleanTrue, если хотите получить атрибуты значения, присутствующего в связке ключей (например, дату создания и дату последнего изменения). Если хотите получить текущее значение элемента, сохраненного вами в связке ключей, а не ключ kSecReturnAttributes, добавьте к словарю ключ kSecReturnData и задайте для него значение kCFBooleanTrue.
Как только ваш словарь будет готов, вы сможете передать его функции SecItemCopyMatching в качестве первого параметра. Второй параметр — это указатель на тот объект, который будет возвращаться функцией. Этот указатель должен относиться к типу CFTypeRef *. Это обобщенный тип данных, и в каждом конкретном случае тип зависит от того, что именно вы передадите функции SecItemCopyMatching в качестве первого параметра. Например, если в вашем словаре содержится ключ kSecReturnAttributes, то вторым параметром этой функции должен быть либо NULL, либо указатель на непрозрачный тип CFDictionaryRef. Если же вместо этого вы передадите словарю ключ kSecReturnData, то второй параметр этой функции должен относиться к типу CFDataRef. Это непрозрачный тип, который будет получать точные данные имеющегося элемента. Затем вы сможете преобразовать эти данные в экземпляр NSString и работать с ним.
Обсуждение
Предположим, вы хотите считать свойства той строки, которую записали в связку ключей в разделе 8.2. Можно написать такой код:
— (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,
(__bridge id)kSecReturnAttributes: (__bridge id)kCFBooleanTrue,
};
CFDictionaryRef valueAttributes = NULL;
OSStatus results = SecItemCopyMatching((__bridge CFDictionaryRef)query,
(CFTypeRef *)&valueAttributes);
NSDictionary *attributes =
(__bridge_transfer NSDictionary *)valueAttributes;
if (results == errSecSuccess){
NSString *key, *accessGroup, *creationDate, *modifiedDate, *service;
key = attributes[(__bridge id)kSecAttrAccount];
accessGroup = attributes[(__bridge id)kSecAttrAccessGroup];
creationDate = attributes[(__bridge id)kSecAttrCreationDate];
modifiedDate = attributes[(__bridge id)kSecAttrModificationDate];
service = attributes[(__bridge id)kSecAttrService];
NSLog(@"Key = %@n
Access Group = %@n
Creation Date = %@n
Modification Date = %@n
Service = %@", key, accessGroup, creationDate,
modifiedDate, service);
} else {
NSLog(@"Error happened with code: %ld", (long)results);
}
self.window = [[UIWindow alloc]
initWithFrame: [[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
После запуска этого приложения на консоль будут выведены примерно такие результаты:
Key = Full Name
Access Group = F3FU372W5M.com.pixolity.ios.cookbook.SecurityApp
Creation Date = 2013-06-09 10:44:55 +0000
Modification Date = 2013-06-09 10:44:55 +0000
Service = com.pixolity.ios.cookbook.SecurityApp
Это, конечно, хорошо, но как считывать актуальную информацию о значении? В подразделе «Решение» данного раздела я уже ответил на этот вопрос: необходимо включить в запрос ключ kSecReturnData. После того как это будет сделано, в качестве второго параметра функция SecItemCopyMatching потребует либо NULL, либо непрозрачную переменную CFDataRef, вот так:
#import «AppDelegate.h»
#import <Security/Security.h>
@implementation AppDelegate
— (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,
(__bridge id)kSecReturnData: (__bridge id)kCFBooleanTrue,
};
CFDataRef cfValue = NULL;
OSStatus results = SecItemCopyMatching((__bridge CFDictionaryRef)query,
(CFTypeRef *)&cfValue);
if (results == errSecSuccess){
NSString *value = [[NSString alloc]
initWithData:(__bridge_transfer NSData *)cfValue
encoding: NSUTF8StringEncoding];
NSLog(@"Value = %@", value);
} else {
NSLog(@"Error happened with code: %ld", (long)results);
}
self.window = [[UIWindow alloc]
initWithFrame: [[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
По умолчанию функция SecItemCopyMatching ищет первое совпадение в связке ключей. Допустим, вы сохранили в связке ключей 10 безопасных элементов класса kSecClassGenericPassword и хотите запросить их все. Как это сделать? Ничего сложного. Просто добавьте ключ kSecMatchLimit в словарь вашего запроса и укажите максимальное количество совпадающих элементов, которые сервисы должны отыскивать в связке ключей. Можно также присвоить этому ключу значение kSecMatchLimitAll — при нем осуществляется поиск всех совпадений. Когда вы внедрите ключ kSecMatchLimit в ваш словарь запроса для функции SecItemCopyMatching, второй параметр этого типа обязательно потребует указатель на непрозрачный тип CFArrayRef, а состоять этот массив будет только из тех элементов, которые вы запросили.
Рассмотрим пример, в котором мы пытаемся найти все элементы связки ключей, удовлетворяющие определенным критериям:
#import «AppDelegate.h»
#import <Security/Security.h>
@implementation AppDelegate
— (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,
(__bridge id)kSecReturnData: (__bridge id)kCFBooleanTrue,
(__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitAll
};
CFArrayRef allCfMatches = NULL;
OSStatus results = SecItemCopyMatching((__bridge CFDictionaryRef)query,
(CFTypeRef *)&allCfMatches);
if (results == errSecSuccess){
NSArray *allMatches = (__bridge_transfer NSArray *)allCfMatches;
for (NSData *itemData in allMatches){
NSString *value = [[NSString alloc]
initWithData: itemData
encoding: NSUTF8StringEncoding];
NSLog(@"Value = %@", value);
}
} else {
NSLog(@"Error happened with code: %ld", (long)results);
}
self.window = [[UIWindow alloc]
initWithFrame: [[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
См. также
Раздел 8.2.
8.4. Обновление значений в связке ключей
Постановка задачи
Вы уже сохранили значение в связке ключей, а теперь хотите обновить его.
Решение
Учитывая, что вы смогли найти значение в связке ключей (см. раздел 8.3), можно схожим образом выполнить функцию SecItemUpdate с двумя параметрами. Ее первым параметром будет словарь вашего запроса, а вторым — словарь, описывающий изменения, которые вы хотите внести в имеющееся значение. Обычно этот обновляющий словарь (второй параметр метода) содержит всего один ключ (kSecValueData). Значением этого словарного ключа являются данные, которые нужно заново установить для имеющегося в связке ключа.