Для хранения пользовательских настроек между запусками приложения, в Cocoa имеется класс NSUserDefaults. Каждому приложению доступен общий экземпляр класса NSUserDefaults. Доступ к этум экземпляру осуществляется с помощью вызова статического метода standardUserDefaults:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSUserDefaults может быть использован для записи, чтения и удаления пользовательских параметров, а также для регистрации значений по умолчанию для параметров.
NSUserDefaults может сохранять, в качестве значений параметров, основные типы: float, double, integer, boolean и объекты стандартных классов: NSData, NSString, NSNumber, NSDate,NSArray, NSDictionary. Объекты классов NSArray, NSDictionary также должны содержать только объекты перечисленных классов. Если необходимо сохранить объекты других типов, используйте метод archivedDataWithRootObject: класса NSKeyedArchiver для получения экземпляра класса NSData NSUserDefaults хранит значения в базе данных параметров пользователя. База данных создается автоматически для каждого пользователя. Для того, чтобы постоянно не дергать базу данных при чтении и изменении параметров, NSUserDefaults использует кэширование.NSUserDefaults возвращаемые неизменяемые объекты, даже если вы устанавливали изменяемый объект в качестве значения.
Получение экземпляра NSUserDefaults
Как было сказано выше, общий экземпляр класса NSUserDefaults возвращает метод standardUserDefaults:. Если экземпляр не был ранее создан, то метод создает его со списком поиска, который состоит из следующих доменов:
- NSArgumentDomain, содержит параметры разобранные из аргументов приложения
- Домен нашего приложения, состоящий из идинтифиатора пакета приложения (Bundle identifier). Например, если наш идентификатор ru.osxdev.testdefs, то и домен будет ru.osxdev.testdefs
- NSGlobalDomain, содержит глобальные параметры доступные во всех приложениях
- Отдельные домены для каждого из предпочтительных языков пользователя
- NSRegistrationDomain, содержит временные параметры со значениями по умолчанию. Значения по умолчанию устанавливаются с помощью метода
registerDefaults:. Параметры из этого домена не сохраняются физически на диск
Созданный объект инициализирован параметрами действительными только для текущего пользователя. Создать экземпляр класса также можно с помощью вызова методов alloc: и init: или initWithUser: :
NSUserDefaults *defaults = [[NSUserDefaults alloc] init];
Метод initWithUser: возвращает экземпляр объекта с параметрами для указанного пользователя. Метод возвращает nil, если нет доступа к указанной учетной записи. Этот метод полезно использовать в приложениях запускаемых суперпользователем и может быть использовано для обновления базы данных параметров для различных пользователей.
Регистрация параметров по умолчанию
В момент запуска приложения необходимо зарегистрировать значения по умолчанию для тех параметров, значения которых должны быть действительными в любом случае. Когда в приложении вы запросите значение параметра, которое не было ранее задано, NSUserDefaults вернет зарегистрированное значение по умолчанию. Регистрация значений по умолчанию осуществляется с помощью метода registerDefaults:dictionary
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSMutableDictionary *defaultValues = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:@"Use3G"]; //... [defaultValues setObject:[NSNumber numberWithBool:YES] forKey:@"UseCache"]; [[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues]; //... }
В метод необходимо передать словарь необходимых параметров и их значений, используемых по умолчанию. Параметры регистрируются в домене NSRegistrationDomain, который добавляется в конец списка поиска.
Сохранение параметров
Методы установки значений:
-setBool:forKey:— устанавливает логическое значение для заданного ключа-setFloat:forKey:— устанавливает значение с плавающей точкой для заданного ключа-setInteger:forKey:— устанавливает целочисленное значения для заданного ключа-setObject:forKey:— устанавливает объект в качестве значения для заданного ключа. В качестве значения могут использоваться только объекты классовNSData,NSString,NSNumber,NSDate,NSArrayиNSDictionary-setDouble:forKey:— устанавливает значение с типом double для заданного ключа-setURL:forKey:— устанавливает URL в качестве значения для указанного ключа. При сохранении экземпляраNSURLпроводятся следующие модификации:- Экземпляры
NSURLне являющиеся ссылками на файлы архивируются с помощью +[NSKeyedArchiver archivedDataWithRootObject:], в качестве корневого элемента в метод передается экземплярNSURL. После этого сохраняемым значением параметра будет экземпляр классаNSData - Экземпляры
NSURLсодержащие ссылки на файл со схемой file: будут обрабатываться как не файловые ссылки, как это описано в первом пункте, но дополнительно в архиве будет сохранена информация которая делает эту ссылку совместимой с системами Mac OS X 10.5, а также минимальные bookmark данные - Для абсолютных путей на файлы в экземплярах
NSURLсо схемой file: будет предпринята попытка конвертировать путь на файл относительно домашнего каталога пользователя. Если это возможно, то в качестве значения будет записана строка, полученная с помощью вызова методаstringByAddingPercentEscapesUsingEncoding: экземпляраNSURL
- Экземпляры
Пример сохранения параметров:
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults setBool:YES forKey:@"UseCache"]; [defaults setObject:[NSDate dateWithTimeIntervalSinceNow:(3600 * 24 * 7)] forKey:@"CacheExpiresIn"];
Чтение параметров
Методы чтения значений:
-arrayForKey:— возвращает массив ассоциированный с указанным ключом. Метод вернет nil, если ключ не найден или ассоциированные с этим ключом данные не являются объектом классаNSArray-boolForKey:— если логическое значение связано с указанным ключом, это значение будет возвращено. Иначе метод вернетNO-dataForKey:— возвращает объект классаNSDataассоциированный с указанным ключом. Метод вернет nil, если ключ не найден или ассоциированные с этим ключом данные не являются объектом классаNSData-dictionaryForKey:— возвращает словарь ассоциированный с указанным ключом. Метод вернет nil, если ключ не найден или ассоциированные с этим ключом данные не являются объектом классаNSArray-floatForKey:— возвращает значение с плавающей точкой ассоциированное с указанным ключом. Метод вернет 0, если ключ не найден-integerForKey:defaultName— возвращает целочисленное значение (NSInteger) ассоциированное с указанным ключом. Метод вернет 0, если указанный ключ не найден-objectForKey:defaultName— возвращает объект ассоциированный с указанным ключом. Метод вернет nil, ели ключ не найден-stringArrayForKey:defaultName— возвращает массив строк ассоциированный с указанным ключом. Метод вернет nil, ели ключ не найден, значение не является объектом классаNSArrayили массив не содержит объектыNSString-stringForKey:defaultName— возвращает строку ассоциированную с указанным ключом. Метод вернет nil, ели ключ не найден или значение не является объектом классаNSString-doubleForKey:defaultName— возвращает double значение ассоциированное с указанным ключом. Метод вернет 0, если ключ не найден-URLForKey:defaultName— возвращает объект классаNSURLассоциированный с указанным ключом. Метод вернет nil, если ключ не найден. В методе при считывании значения используется следующая логика:- Если значение ассоциированное с указанным ключом является объектом класса
NSData, то этот объект используется в качестве аргумента методаunarchiveObjectWithData:([NSKeyedUnarchiver:unarchiveObjectWithData]). Если объект классаNSDataможет быть разархивирован какNSURL, то метод вернет объект классаNSURL, в противном случае метод вернет nil. - Если ассоциированное с ключом значение является ссылкой на файл, будет создана объект класса
NSURLс ссылкой на файл, но его bookmark данные не будут зарезолвлены, пока объект не будет использован - Если ассоциированное с ключом значением является строкой, начинающейся с символа ~, то строка будет развернута в полный путь с помощью вызова метода
stringByExpandingTildeInPath: объектаNSString, а затем из полученного значения будет создан объект классаNSURLсо схемой file:
- Если значение ассоциированное с указанным ключом является объектом класса
Поиск значений осуществляется в доменах списка поиска в порядке в котором они были добавлены в список. Получить все параметры из всех доменов поиска можно вызвав метод dictionaryRepresentation:. Метод возвращает словарь со всеми параметрами.
Пример чтения параметров:
NSUserDefaults = [NSUserDefaults standardUserDefaults]; if ([defaults boolForKey:@"Use3G"]) { // ... } else { //.. }
Удаление параметров
Удаление параметров осуществляется с помощью метода removeObjectForKey:. Метод принимает единственный аргумент — название ключа.
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults removeObjectForKey:@"Use3G"]; [defaults removeObjectForKey:@"UseCache"];
Синхронизация
Синхронизация данных, хранящихся в кэше, с данными, хранящимися в базе данных параметров, происходит автоматически с определенными временными интервалами. Если данные необходимо синхронизировать немедленно, не дожидаясь пока это произойдет автоматически, необходимо вызвать метод synchronize:. Метод вернет YES, если данные были успешно синхронизированы, иначеNO.
Управление доменами
Домены разделяются на постоянные и не постоянные. Постоянные домены существуют между вызовами приложения. Непостоянные домены не сохраняются между вызовами приложения. Например, постоянным доменам являются NSGlobalDomain, домен равный идентификатору вашего приложения, а непостоянным — NSRegistrationDomain, NSArgumentDomain. Методы управления параметрами связанными с постоянными доменами:
-persistentDomainNames— возвращает массив строк с названиями текущих постоянных доменов-persistentDomainForName— возвращает словарь с ключами и значениями параметров для постоянного домена, название которого было указано-removePersistentDomainForName— удаляет все параметры связанные с указанным постоянным доменном-setPersistentDomain:forName:— устанавливает параметры, переданные в словаре, в указанный постоянный домен. Название домена должно быть равным идентификатору пакета приложения (Bundle identifier)
Методы управления параметрами связанными с непостоянными доменами:
-volatileDomainNames— возвращает массив строк с названиями текущих непостоянных доменов-volatileDomainForName— возвращает словарь с ключами и значениями параметров для непостоянного домена, название которого было указано-removeVolatileDomainForName— удаляет все параметры связанные с указанным непостоянным доменном-setVolatileDomain:forName:— устанавливает параметры, переданные в словаре, в указанный непостоянный домен
NSUserDefaults также позволяет использовать установленные параметры между приложениями. Если вам необходимо из приложения B получить доступ к параметрам приложения A, то в приложение B, в список поиска, вам необходимо добавить домен приложения A. Делается это с помощью метода addSuiteNamed:. Данные связанные с добавленным доменом доступны только для чтения. Метод принимает в качестве аргумента название домена. Обычно это идентификатор приложения. Для примера в своем приложении мы можем получить пути к базам данных iTunes:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults addSuiteNamed:@"com.apple.iApps"];
NSLog (@"Databases: %@", [defaults objectForKey:@"iTunesRecentDatabasePaths"]);
Удалить домен из списка поиска можно с помощью метода removeSuiteNamed:. Метод принимает в качестве аргумента название удаляемого из списка поиска домена.
Уведомления
NSUserDefault посылает уведомление NSUserDefaultsDidChangeNotification когда происходит изменение значения параметра в постоянном домене. Объект уведомления — NSUserDefaults. Уведомление не содержит словарь userInfo. Пример использования уведомления:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(defaultsChanged:) name:NSUserDefaultsDidChangeNotification object:nil];
}
- (void)defaultsChanged:(NSNotification *)notification {
NSUserDefaults *defaults = (NSUserDefaults *)[notification object]; // используем
}
Автор: Антон Добкин