Ответ
Персистентность данных — это способность приложения сохранять своё состояние (данные, настройки) между запусками, после перезагрузки устройства или даже после удаления и повторной установки приложения (если данные синхронизированы с облаком).
Основные способы хранения данных в iOS:
| Способ | Для чего используется | Ключевые особенности |
|---|---|---|
UserDefaults |
Небольшие простые данные: настройки, флаги, счётчики. | Быстро, просто. Не для чувствительных или больших данных. |
Файловая система (FileManager) |
Документы, изображения, аудио, любые пользовательские файлы. | Прямой доступ к файлам. Использует песочницу приложения. |
| Keychain Services | Чувствительные данные: пароли, токены, сертификаты. | Безопасное зашифрованное хранилище. Сохраняется между установками. |
| Core Data | Сложные объектные графы, реляционные данные, с большими наборами. | Объектно-графовый фреймворк. SQLite "под капотом". Мощные запросы. |
| SQLite (через обёртки) | Прямая работа с реляционной БД. | Полный контроль над SQL. Требует знания SQL. |
| Realm | Альтернатива Core Data для объектного хранения. | Простой API, высокая производительность. |
Примеры кода:
1. UserDefaults:
// Запись
UserDefaults.standard.set("John", forKey: "userName")
UserDefaults.standard.set(true, forKey: "isOnboardingCompleted")
// Чтение
let name = UserDefaults.standard.string(forKey: "userName")
let isCompleted = UserDefaults.standard.bool(forKey: "isOnboardingCompleted")
2. Файловая система (сохранение Data):
func saveDataToFile(_ data: Data, fileName: String) -> URL? {
guard let documentsDir = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first else {
return nil
}
let fileURL = documentsDir.appendingPathComponent(fileName)
do {
try data.write(to: fileURL)
return fileURL
} catch {
print("Ошибка сохранения: (error)")
return nil
}
}
3. Keychain (используя библиотеку KeychainAccess для простоты):
import KeychainAccess
let keychain = Keychain(service: "com.yourapp.bundleid")
// Сохранить токен
keychain["authToken"] = "eyJhbGciOiJ..."
// Прочитать токен
let token = keychain["authToken"]
Критерии выбора:
- Объём данных: Маленький (
UserDefaults) vs. Большой (Core Data/Файлы). - Структура: Простые типы vs. Сложные объектные связи.
- Безопасность: Keychain для секретов.
- Необходимость в запросах: Core Data/SQLite для сложной фильтрации и сортировки.
- Производительность и простота использования.
Ответ 18+ 🔞
А, слушай, про персистентность! Ну это ж, блядь, самая соль, когда твоё приложение не обосрётся и не забудет всё, как только пользователь его закроет. Представь: зашёл, настроил, вышел — а нахуй, опять логиниться? Пиздец, пользователь снесёт приложение к ебеням.
Вот тебе, сука, шпаргалка, как эту самую память устроить, чтобы всё помнилось. Выбирай по обстоятельствам, а то накосячишь — будешь потом как Герасим, с мешком на озере стоять.
Основные конторы для хранения добра:
| Способ | Для какой хуйни | Что важно |
|---|---|---|
UserDefaults |
Для мелочёвки: галочки, последний логин, какая-то хуйня-счётчик. | Быстро, просто. Но если туда фотки пихать начнёшь — получишь пиздюлей от системы. |
Файловая система (FileManager) |
Для всего, что можно потрогать: документы, картинки, мемы, записи голоса. | Работаешь с файлами напрямую. Всё в песочнице, на чужие файлы не залезешь. |
| Keychain Services | Для самого ценного: пароли, токены доступа, номера карт (ох, ёпта). | Зашифровано, безопасно. Даже если приложение удалят и поставят заново — данные могут сохраниться. |
| Core Data | Для сложных схем, где объекты друг на друга ссылаются, и их овердохуища. | Мощная бандура, под капотом часто SQLite. Умеет красиво связывать сущности и делать умные запросы. |
| SQLite (напрямую) | Для тех, кто в SQL как рыба в воде и хочет тотального контроля. | Сам всё делаешь, сам и отвечаешь. Ошибёшься в запросе — получишь nil и депрессию. |
| Realm | Для тех, кому Core Data показался слишком весёлым. | Говорят, API попроще и побыстрее. Попробуй, хули. |
Ну и примерчики, чтобы не быть просто пиздаболом:
1. UserDefaults (для ленивых):
// Запихнули
UserDefaults.standard.set("Василий", forKey: "userName")
UserDefaults.standard.set(true, forKey: "isOnboardingCompleted")
// Достали
let name = UserDefaults.standard.string(forKey: "userName")
let isCompleted = UserDefaults.standard.bool(forKey: "isOnboardingCompleted")
Вот, видишь? Ничего сложного. Но если сюда массив из 10 000 объектов сунешь — приложение будет запускаться как черепаха в сиропе.
2. Файловая система (сохраняем Data):
func saveDataToFile(_ data: Data, fileName: String) -> URL? {
guard let documentsDir = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask).first else {
return nil
}
let fileURL = documentsDir.appendingPathComponent(fileName)
do {
try data.write(to: fileURL)
return fileURL
} catch {
print("Ошибка сохранения: (error)") // А тут лучше не принтом, а нормально ошибку обработать, а то пользователь нихуя не поймёт
return nil
}
}
Всё, файл твой. Лежит в песочнице. Можешь им трясти.
3. Keychain (через библиотечку KeychainAccess, а то там свой API — просто пиздец):
import KeychainAccess
let keychain = Keychain(service: "com.yourapp.bundleid")
// Спрятали токен
keychain["authToken"] = "eyJhbGciOiJ..."
// Достали токен
let token = keychain["authToken"]
Вот это уже серьёзно. Это уже не просто файлик, это, блядь, сейф. Для паролей и прочей конфиденциальной хуйни.
Как же выбрать, ёпта?
- Сколько вешать в граммах? Мало —
UserDefaults. Много — Core Data или файлы. - Что за структура? Просто число/строка или сложная сеть объектов, которые друг друга ебут?
- А безопасность? Если это пароль — только Keychain, иначе ты, прости, мудак.
- Нужны ли сложные выборки? Типа «покажи всех пользователей из Москвы, купивших синий ковёр после вторника» — тогда Core Data или SQLite.
- Не хочешь ебаться? Выбирай самое простое, что решает задачу. Не гонись за модным, если можно обойтись
UserDefaults.
Вот и вся магия. Главное — не храни пароли в UserDefaults, а то потом будешь как тот чувак, который ключи от сейфа на видное место кладёт. Удачи, не обосрись.