Minggu ini saya ingin berbicara tentang pemodelan lapisan data di SwiftUI. Saya sudah selesai mengerjakan aplikasi pertama saya, yang saya buat hanya menggunakan SwiftUI. Sekarang saya dapat berbagi cara membuat lapisan model menggunakan objek Store yang saya gunakan saat mengembangkan aplikasi NapBot.
Simpan Objek
Menyimpan objek bertanggung jawab untuk mempertahankan negara dan memberikan tindakan untuk mengubahnya. Anda dapat memiliki sebanyak mungkin objek Store yang Anda butuhkan, terutama yang sederhana dan bertanggung jawab atas sebagian kecil dari kondisi aplikasi Anda. Misalnya, Anda mungkin memiliki
SettingsStore untuk menyimpan status pengaturan pengguna dan
TodoStore untuk menyimpan tugas kustom.
Untuk membuat objek Store, Anda harus membuat kelas yang sesuai dengan protokol
ObservableObject . Protokol ObservableObject memungkinkan SwiftUI untuk mengamati dan menanggapi perubahan data. Untuk mempelajari lebih lanjut tentang ObservableObject, lihat artikel "
Mengelola Aliran Data di SwiftUI ". Mari kita lihat contoh sederhana objek
SettingsStore .
import Foundation import Combine final class SettingsStore: ObservableObject { let objectWillChange = PassthroughSubject<Void, Never>() @UserDefault(Constants.UserDefaults.sleepGoal, defaultValue: 8.0) var sleepGoal: Double @UserDefault(Constants.UserDefaults.notifications, defaultValue: true) var isNotificationsEnabled: Bool private var didChangeCancellable: AnyCancellable? override init() { super.init() didChangeCancellable = NotificationCenter.default .publisher(for: UserDefaults.didChangeNotification) .map { _ in () } .receive(on: DispatchQueue.main) .subscribe(objectWillChange) } }
Dalam contoh kode di atas, kita memiliki kelas
SettingsStore , yang menyediakan akses ke pengaturan pengguna. Kami juga menggunakan
didChangeNotification untuk memberi tahu SwiftUI setiap kali pengguna mengubah pengaturan default.
Penggunaan diperpanjang
Mari kita lihat kegunaan lain dari objek toko dengan membuat aplikasi
Todo sederhana. Kita perlu membuat objek toko yang menyimpan daftar tugas dan memberikan tindakan untuk mengubahnya, misalnya menghapusnya dan memfilternya.
import Foundation import Combine struct Todo: Identifiable, Hashable { let id = UUID() var title: String var date: Date var isDone: Bool var priority: Int } final class TodosStore: ObservableObject { @Published var todos: [Todo] = [] func orderByDate() { todos.sort { $0.date < $1.date } } func orderByPriority() { todos.sort { $0.priority > $1.priority } } func removeCompleted() { todos.removeAll { $0.isDone } } }
Ada kelas
TodosStore yang sesuai dengan protokol ObservableObject. TodosStore menyediakan beberapa tindakan untuk mengubah keadaannya, kita dapat menggunakan metode ini dari pandangan kita. Secara default,
SwiftUI memperbarui tampilan setiap kali bidang
@Published berubah . Inilah sebabnya mengapa array elemen
Todo ditetapkan sebagai
@Published . Segera setelah kami menambah atau menghapus elemen dari array ini, SwiftUI akan memperbarui tampilan yang berlangganan
TodosStore .
Sekarang Anda dapat membuat tampilan yang menampilkan daftar tugas dan tindakan seperti menandai tugas sebagai selesai, menghapus dan mengubah urutan tugas yang ditampilkan. Mari kita mulai dengan membuat tampilan yang menampilkan judul tugas dan peralihan untuk menandai tugas sebagai selesai.
import SwiftUI struct TodoItemView: View { let todo: Binding<Todo> var body: some View { HStack { Toggle(isOn: todo.isDone) { Text(todo.title.wrappedValue) .strikethrough(todo.isDone.wrappedValue) } } } }
Dalam contoh di atas,
Binding digunakan untuk memberikan referensi, misalnya akses ke tipe nilai. Dengan kata lain, beri akses tulis ke elemen todo.
TodoItemView tidak memiliki instance dari struktur Todo, tetapi ia memiliki akses tulis ke TodoStore melalui
Binding .
import SwiftUI struct TodosView: View { @EnvironmentObject var store: TodosStore @State private var draft: String = "" var body: some View { NavigationView { List { TextField("Type something...", text: $draft, onCommit: addTodo) ForEach(store.todos.indexed(), id: \.1.id) { index, _ in TodoItemView(todo: self.$store.todos[index]) } .onDelete(perform: delete) .onMove(perform: move) } .navigationBarItems(trailing: EditButton()) .navigationBarTitle("Todos") } } private func delete(_ indexes: IndexSet) { store.todos.remove(atOffsets: indexes) } private func move(_ indexes: IndexSet, to offset: Int) { store.todos.move(fromOffsets: indexes, toOffset: offset) } private func addTodo() { let newTodo = Todo(title: draft, date: Date(), isDone: false, priority: 0) store.todos.insert(newTodo, at: 0) draft = "" } }
Sekarang kita memiliki
TodosView , elemen yang menggunakan komponen
Daftar untuk menampilkan tugas. Komponen
Daftar juga menyediakan penataan ulang dan penghapusan. Hal lain yang menarik adalah fungsi
diindeks () . Fungsi ini mengembalikan kumpulan elemen dengan indeksnya. Kami menggunakannya untuk mengakses item di toko melalui Binding. Berikut adalah sumber lengkap ekstensi ini.
import Foundation struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection { typealias Index = Base.Index typealias Element = (index: Index, element: Base.Element) let base: Base var startIndex: Index { base.startIndex } var endIndex: Index { base.endIndex } func index(after i: Index) -> Index { base.index(after: i) } func index(before i: Index) -> Index { base.index(before: i) } func index(_ i: Index, offsetBy distance: Int) -> Index { base.index(i, offsetBy: distance) } subscript(position: Index) -> Element { (index: position, element: base[position]) } } extension RandomAccessCollection { func indexed() -> IndexedCollection<Self> { IndexedCollection(base: self) } }
Lingkungan adalah kandidat yang ideal untuk menyimpan objek toko. Lingkungan dapat membaginya di antara beberapa tampilan tanpa implementasi eksplisit melalui metode
init . Untuk mempelajari lebih lanjut tentang manfaat Lingkungan di SwiftUI, lihat artikel "
Fitur Lingkungan di SwiftUI ".

Kesimpulan
Artikel ini membahas cara untuk memodelkan keadaan aplikasi menggunakan beberapa objek
toko . Saya sangat menyukai kesederhanaan pendekatan ini dan betapa mudahnya untuk mengukur aplikasi Anda dengan menambahkan lebih banyak objek toko. Saya harap Anda menikmati artikel ini.