App Sandbox & App Bundle
Sandbox
Sandbox(песочница) - функция безопасности для iOS. Все наши данные и части нашего приложения, файлы, бандлы. Sandbox инкапсулирует их.
Для того чтобы нам получить данные за пределами песочницы его необходимо запросить.
Когда пользователь запрещает доступ, эти настройки можно изменить в Settings самого приложения
Внутри sandbox также есть свои директории, с которыми можно работать.
OS профили:
*.metadata.plist - описание политики безопасности
Location: ~/Library/Containers/<bundle_id>
Папки:
Documents
- отличное место для сохранения пользовательских данных. Вы должны сами побеспокоится о своевременной очистке папки. Можно самому устроить иерархию папок.Library
- содержит папки\Application Support
и \Caches. Вы имеете доступ только к ним. (Can be purged by operating system in case of memory warning.)tmp
- временное хранилище
!!ВАЖНО!!! папки Temp и Cashes система будет чистить сама. Обычно, Temp будет чистить после закрытия приложения. В Cashes данные могут хранится дольше. Единсвенное правильное место для сохранения данных - папка Documents.
Можно узнать путь к папкам вызвав функцию:
NSLog(@"%@", NSHomeDirectory());
Результат будет примерно следующим:
/var/mobile/Containers/Application/08AA3B09- FB31-4DA9-9988-A2AB6BDDAE70
На симуляторе результат будет выглядеть примерно так:
/Users/your_user_name/Library/Developer/CoreSimulator/Devices/5-XXXX-XXXX-XXXX-XXXXXXXXXXXX/data/Containers/ Data/Application/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
URL for temp directory
NSURL *url = [NSURL fileURLWithPath:NSTemporaryDirectory()];
Bundle
Bundle — это представление кода и ресурсов, хранящихся в каталоге проекта на диске (*.h, *.m, *.xib и.т.д). Bundle находится внутри sandbox.
NSUserDefaults
По умолчанию у нас есть пользовательское хранилище, база данных, где вы храните пары ключ-значение постоянно при вызовах вашего приложения. Это хранилище представляет собой, ни что иное как *.plist файл.
Поддерживает следующие форматы данных:
- NSData
- NSString
- NSNumber
- NSDate
- NSArray
- NSDictionary
Если нужно сохранить объект, его необходимо привести к любом вышеописанному формату.
Что бы записать или считать обекты, необходимо обратится к следующим методам:
[[NSUserDefaults standardUserDefaults] setObject:@"OBJECT"forKey:@"KEY"];
[[NSUserDefaults standardUserDefaults] objectForKey:@"KEY"];
Записанные значение можно наблюдать, используя механизм key-value observing.
У NSUserDefaults есть метод для сохранения состояния sychonized(). В ранних версиях его необходимо было вызывать всегда, но сейчас его необходимо вызывать только для принудительного сохранения состояния.
Все возвращаемые объекты NSUserDefaults имутабельны.
В NSUserDefaults имеется возможность зарегистрировать значение по умолчанию для определенного ключа.
NSUserDefaults *standartDefaults = [NSUserDefaults standardUserDefaults];
if (![standartDefaults objectForKey:@"timeout"]) {
[standartDefaults setObject:timeout forKey:@"timeout"];
}
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
@"timeout": timeout
}];
NSKeyedArchiver
NSKeyedArchiver
, подкласс NSCoder
, предоставляет способ кодирования объектов (и скалярных значений) в независимый от архитектуры формат, который можно сохранить в файле. Когда вы архивируете набор объектов, информация о классе и переменные экземпляра для каждого объекта записываются в архив.
Сопутствующий класс NSKeyedUnarchiver декодирует данные в архиве и создает набор объектов, эквивалентный исходному набору.
Пример использования NSKeyedUnarchiver
1) Определить в своей классе требуемые методы
+ (BOOL)supportsSecureCoding {
return true;
}
- (void)encodeWithCoder:(nonnull NSCoder *)coder {
[coder encodeInteger:self.age forKey:@"age"];
[coder encodeObject:self.firstName forKey:@"firstName"];
[coder encodeObject:self.avatar forKey:@"avatar"];
}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
if (self = [super init]) {
_firstName = [coder decodeObjectOfClass:NSString.class forKey:@"firstName"];
_avatar = [coder decodeObjectOfClass:NSImage.class forKey:@"avatar"];
_age = [coder decodeIntegerForKey:@"age"];
}
return self;
}
2) использовать методы NSKeyedUnarchiver
// encode object
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user requiringSecureCoding:true error:&error];
// decode object
User *user = [NSKeyedUnarchiver unarchivedObjectOfClass:User.class fromData:data error:&error];
Ключи, предоставляемые закодированным значениям, должны быть уникальными только в рамках текущего объекта. NSKeyedUnarchiver является иерархическим, поэтому ключи, используемые объектом A для кодирования переменных экземпляра, не конфликтуют с ключами, используемыми объектами B, даже если A и B являются экземплярами одного и того же класса. Однако в пределах одного объекта ключи, используемые подклассом, могут конфликтовать с ключами, используемыми в его суперклассах.