На WWDC Apple анонсировала новый фреймворк для работы с данными, обертку вокруг CoreData — SwiftData. Он позволяет быстро добавить персистентность в ваше приложение, с минимальным количеством кода и без внешних зависимостей.
Вы можете использовать SwiftData для сохранения данных вашего приложения для офлайн использования или для кэширования временных данных. Фреймворк полностью сфокусирован на коде, без внешних форматов файлов, и использует новую систему макросов Swift для бесшовной работы с API.
Создание модели
@Model — это макрос, который помогает определить схему вашей модели.
Нам нужно добавить макрос Model перед объявлением вашего класса, чтобы преобразовать Swift-класс в хранимую модель, управляемую SwiftData.
@Model class User { var id: UUID var firstName: String var lastName: String var company: Company init(firstName: String, lastName: String, company: Company) { self.id = UUID() self.firstName = firstName self.lastName = lastName self.company = company } } @Model class Company { var id: UUID var companyName: String var designation: String init(companyName: String, designation: String) { self.id = UUID() self.companyName = companyName self.designation = designation } }
Контейнер модели
Это объект, управляющий схемой и конфигурацией хранилища моделей.
Контейнер моделей устанавливается в WindowGroup. Мы можем передавать туда несколько моделей данных.
@main struct SwiftData_ExampleApp: App { var body: some Scene { WindowGroup { NavigationStack { UserList() } } .modelContainer(for: [User.self, Company.self]) } }
Контекст модели
ModelContext — это объект, позволяющий извлекать, вставлять и удалять модели, а также сохранять любые изменения на диске.
Все в SwiftData происходит с контекстом модели. По сути, объект похож на контекст представления в CoreData.
@Environment(\.modelContext) private var modelContext
Запрос
Используйте @Query в представлениях SwiftUI для получения данных.
SwiftData и SwiftUI работают вместе, чтобы обеспечить живое обновление ваших представлений при изменении базовых данных, без необходимости вручную обновлять результаты.
Вы можете добавить predicate к запросу для фильтрации элементов, sort для сортировки, установить order — сортировать в прямом или обратном порядке, а также задать animation для изменений пользовательского интерфейса, которые происходят в результате изменения полученных результатов.
@Query(sort: \User.firstName, order: .forward, animation: .smooth) var users: [User]
Ниже приведен пример получения пользователей и отображения их в списке:
struct UserList: View { @Environment(\.modelContext) private var modelContext @Query(sort: \User.firstName, order: .forward, animation: .smooth) var users: [User] var body: some View { VStack { if users.isEmpty { Text("Press '+' to add new user") } else { List(users) { user in NavigationLink { EditUser(user: user) } label: { VStack(alignment: .leading) { Text("\(user.firstName) \(user.lastName)") .fontWeight(.bold) .font(.headline) Text("Company: \(user.company.companyName)") .fontWeight(.regular) .font(.caption) Text("Designation: \(user.company.designation)") .fontWeight(.regular) .font(.caption2) } .swipeActions { Button("Delete", role: .destructive) { modelContext.delete(user) } } } } } } .toolbar { NavigationLink { CreateUser() } label: { Text("+") .fontWeight(.bold) .font(.title) } } } }
Вставка, обновление и удаление данных с использованием контекста.
Нам не нужно явно вызывать сохранение явно, SwiftData автоматически сохраняет modelcontext.
//insert let user = User(firstName: firstName, lastName: lastName, company: Company(companyName: companyName, designation: designation)) modelContext.insert(user) //update user.lastName = "Something" //delete modelContext.delete(user)
Ниже приведен пример вставки объекта в SwiftData:
struct CreateUser: View { @Environment(\.modelContext) private var modelContext @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> @State private var firstName: String = "" @State private var lastName: String = "" @State private var companyName: String = "" @State private var designation: String = "" var body: some View { VStack(spacing: 20) { TextField("First Name", text: $firstName) .textFieldStyle(.roundedBorder) TextField("Last Name", text: $lastName) .textFieldStyle(.roundedBorder) TextField("Company Name", text: $companyName) .textFieldStyle(.roundedBorder) TextField("Designation", text: $designation) .textFieldStyle(.roundedBorder) Spacer() } .padding(20) .navigationTitle("Create User") .toolbar { Button(action: { let user = User(firstName: firstName, lastName: lastName, company: Company(companyName: companyName, designation: designation)) modelContext.insert(user) do { try modelContext.save() presentationMode.wrappedValue.dismiss() } catch { print(error.localizedDescription) } }, label: { Text("Save") }) } } }
Ключевые моменты SwiftData
- Декларативный код
- Быстрый, эффективный и безопасный
- Разработан для бесшовной интеграции со SwiftUI
- Синхронизация с помощью CloudKit