Где в iOS-приложении можно хранить коллекцию данных?

Ответ

Выбор хранилища зависит от объёма данных, структуры, требований к скорости и необходимости сохранения между запусками.

Место хранения Тип данных / Объём Ключевой API Когда использовать
Оперативная память (RAM) Временные данные, кэш. Переменные в классе (Array, Dictionary). Данные нужны только во время работы приложения. Самый быстрый доступ.
UserDefaults Небольшие коллекции примитивов или Codable-объектов. UserDefaults.standard. Настройки пользователя, флаги, простые списки (< 100 КБ).
Файловая система (Documents/ Caches) Любые данные среднего и большого размера. FileManager, Codable + JSONEncoder/PropertyListEncoder. Коллекции объектов, которые нужно сохранять, но не требуют сложных запросов (например, сохранённые статьи, профили).
Базы данных (SQLite, Core Data, Realm) Большие, структурированные коллекции со связями. CoreData, GRDB, Realm. Данные с отношениями (пользователи + заказы), требующие сложных запросов, сортировки, фильтрации.
Ключевое хранилище (Keychain) Чувствительные данные (пароли, токены). Keychain Services. Маленькие защищённые коллекции (например, список access token).

Пример для файловой системы (Codable):

struct Task: Codable {
    let id: UUID
    let title: String
}

// Сохранение массива задач
let tasks: [Task] = // ...
let url = FileManager.default
    .urls(for: .documentDirectory, in: .userDomainMask)[0]
    .appendingPathComponent("tasks.json")

let encoder = JSONEncoder()
do {
    let data = try encoder.encode(tasks)
    try data.write(to: url)
} catch {
    print("Ошибка сохранения: (error)")
}

Рекомендация: Начинайте с простого решения (память → UserDefaults → файл). Переходите к базе данных при появлении требований к запросам или объёму.

Ответ 18+ 🔞

Ну слушай, вот сидишь ты, такой весь в себе, пишешь приложение, и тут — бац! — нужно куда-то данные пихнуть. А куда, блядь? Выбор-то, как в хорошем винесказе, на любой вкус и цвет, только вот если ошибешься — потом будешь локти кусать, пока приложение твоё, как черепаха по асфальту, ползает.

Смотри, табличка тут для тебя, но она сухая, как сухарь в пустыне. Давай я её на человеческий переведу, с примесью жизненного опыта, так сказать.

Оперативная память (RAM) — это как твой карман. Кинул туда ключи от квартиры (массив какой-нибудь) — они тут, под рукой, мгновенно. Но вышел на улицу, приложение закрыл — и всё, карман пуст, ключи нахуй пропали. Быстро, но не надолго. Для кэша, временных плюшек — самое то.

UserDefaults — это твой старый, потрёпанный блокнотик на холодильнике. Записал туда «Купить хлеб» или «Тема тёмная». Объём — как у золотой рыбки память, три строчки. Больше 100 килобайт пихать — он тебе такую дичь устроит с производительностью, что мама не горюй. Только для настроек, флажков и прочей ерунды.

Файловая система — вот это уже серьёзно. Это твой личный сейф в подвале (папка Documents) или сарай для хлама (Caches). Можешь туда хоть всю библиотеку Британскую в JSON'е засунуть. Доступ не мгновенный, но надёжный. Сохранил коллекцию мемов — и они там, ждут тебя после перезапуска. Главное — самому всё организовывать: кодировать, писать, читать. Автоматом нихуя не будет.

Базы данных (SQLite, Core Data) — это, сука, уже целый логистический склад с роботами-погрузчиками. У тебя данных — овердохуища, они связаны между собой (пользователи, заказы, котики), и тебе нужно из этой кучи моментально находить «всех котиков старше года, которые заказали сардины в прошлый вторник». Вот для этого они и нужны. Сложно? Ебать, как сложно. Но если масштаб пошел — без них ты просто сдохнешь под грузом своих же JSON-файлов.

Keychain — это бронированная комната в швейцарском банке. Только для самого ценного: паролей, токенов, ключей шифрования. Туда просто так не залезешь. Объём маленький, но безопасность — на уровне.

А теперь, чтобы не быть голословным, смотри, как в файл эту всю хрень пихать, если ты решил, что база данных — это пока как танцы в балете, слишком сложно:

struct Task: Codable {
    let id: UUID
    let title: String
}

// Сохранение массива задач
let tasks: [Task] = // ...
let url = FileManager.default
    .urls(for: .documentDirectory, in: .userDomainMask)[0]
    .appendingPathComponent("tasks.json")

let encoder = JSONEncoder()
do {
    let data = try encoder.encode(tasks)
    try data.write(to: url)
} catch {
    print("Ошибка сохранения: (error)")
}

Видишь? Ничего сверхъестественного. Codable всё закодировал, FileManager путь нашёл, записали и пошли дальше.

И главный совет, как от мудрого, но слегка подуставшего гуру: не гони сразу на Core Data, как ошалелый. Начни с простого. Сделал через переменные в памяти — работает? Отлично. Понял, что нужно между запусками сохранять — перетащи в UserDefaults. Объём вырос, или структура стала сложной — выгружай в файл. А когда почувствуешь, что в этих файлах ты уже тонешь, как Герасим Муму в пруду, вот тогда уже, блядь, берись за нормальную базу. Так и нервы целее будут, и архитектура не превратится в одно большое говно.