Для хранения пользовательских настроек месжду запусками приложения в 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]; // используем
}