В SwiftUI существует два способа сохранения небольших объектов данных между перезапусками приложения (@AppStorage и @SceneStorage). Например, настройки пользователя на уровне всего приложения или данные из регистрационной формы на уровне сцены (scene).
SceneStorage
Обертка @SceneStorage подходит для сохранения и восстановления состояния экрана между запусками приложения или для хранения небольших объемов данных в рамках отдельных экземпляров сцены приложения, например, приложение прерывается телефонным звонком или текстовым сообщением и помещает приложение на задний план.
Следующий код объявляет @SceneStorage переменную для хранения значения String с использованием comment как имя ключа, значением по умолчанию - пустая строка.
@SceneStorage("comment") var comment: String = ""
После объявления, переменную можно использоваться в сочетании с TextEditor следующим образом
var body: some View {
TextEditor(text: $comment).padding()
}
Это гарантирует, что любой текст, введенный в текстовое поле, останется в сцене при перезапуске приложения.
При работе с хранилищем сцен важно помнить, что каждый экземпляр сцены имеет собственное хранилище, которое независимо от других сцен.
AppStorage
Обертка @SceneStorage позволяет каждой отдельной сцене иметь собственную копию данных. Другими словами, данные, хранящиеся в одной сцене, недоступны для других сцен в приложении.
Обертка @AppStorage используется для хранения данных, которые доступны во всем приложении. Для этого используется UserDefaults которая уже много лет доступна в iOS. И позволяет сохранять пользовательские настройки по умолчанию (например, языковые настройки или выбор темы).
Обертка @AppStorage так использует строковую переменную для ключа.
@AppStorage("language") var language: String = ""
По умолчанию данные будут сохраненны в стандартном хранилище UserDefaults. Однако возможно указать App Group, в которой будут храниться данные.
Сохранение произвольного типа данных
Обертка @AppStorage и @SceneStorage позволяют сохранять значения только определенных типов. В частности, типы Bool, Int, Double, String, URL и Data. Это означает, что любой другой тип, который необходимо сохранить, должен быть сначала закодирован как Data для сохранения и последующего декодирования при извлечении.
Следующее пример демонстрирует объявление структуры и ее инициализацию
struct Movie {
var title: String
var year: Int
}
var cinema = Movie(title: "The Godfather", year: 1972)
Экземпляр должен быть закодирован и инкапсулирован в экземпляр Data, прежде чем его можно будет сохранить. Ключевым требованием является соответствие Encodable и Decodable протоколам или Codable.
struct Movie: Codable {
var title: String
var year: Int
}
Следующий примере использует JSON encoder для кодирования экземпляра cinema и его сохранения с помощью обертки @AppStorage.
@AppStorage("cinema") var cinemaStore: Data = Data()
let encoder = JSONEncoder()
if let data = try? encoder.encode(cinema) {
cinemaStore = data
}
Для извлечения данных из хранилища используем JSON decoder.
let decoder = JSONDecoder()
if let movie = try? decoder.decode(Movie.self, from: cinemaStore) {
cinema = movie
}