В 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 }