
"Saya merobek data inti, ini adalah cara kerjanya"
- Josh Holtz
"Butik sangat mudah diimplementasikan dan membuat kegigihan menjadi mudah. Ini menjadi tambahan pertama saya untuk setiap proyek yang saya mulai.
- Tyler Hillsman
"Boutique telah menjadi sangat berharga, saya menggunakannya di setiap proyek sisi sekarang. Tidak harus peduli dengan kegigihan itu hebat dan biaya memulai praktis nol."
- Romain Pouclet
Jika Anda menganggap butik berharga, saya akan sangat menghargainya jika Anda akan mempertimbangkan untuk membantu mensponsori pekerjaan open source saya, sehingga saya dapat terus mengerjakan proyek -proyek seperti Boutique untuk membantu pengembang seperti Anda.
Boutique adalah perpustakaan kegigihan yang sederhana namun kuat, serangkaian kecil pembungkus dan jenis properti yang memungkinkan membangun aplikasi yang sangat sederhana untuk negara bagian untuk SwiftUi, Uikit, dan Appkit. Dengan memori ganda berlapis-lapis + Disk Caching Architecture Boutique menyediakan cara untuk membangun aplikasi yang diperbarui secara real time dengan penyimpanan offline penuh hanya dalam beberapa baris kode menggunakan API yang sangat sederhana. Boutique dibangun di atas Bodega, dan Anda dapat menemukan aplikasi demo yang dibangun di atas arsitektur toko pengontrol tampilan model dalam repo ini yang menunjukkan kepada Anda cara membuat aplikasi SwiftUi yang siap-offline hanya dalam beberapa baris kode. Anda dapat membaca lebih lanjut tentang pemikiran di balik arsitektur di posting blog ini yang menjelajahi arsitektur MVCS.
Butik hanya memiliki satu konsep yang perlu Anda pahami. Saat Anda menyimpan data ke Store data Anda akan bertahan secara otomatis untuk Anda dan diekspos sebagai array cepat biasa. Pembungkus properti @StoredValue dan @SecurelyStoredValue bekerja dengan cara yang sama, tetapi alih -alih array mereka bekerja dengan nilai -nilai cepat tunggal. Anda tidak perlu memikirkan database, semua yang ada di aplikasi Anda adalah array atau nilai cepat reguler menggunakan model aplikasi Anda, dengan kode langsung yang terlihat seperti aplikasi lainnya.
Anda mungkin terbiasa dengan Store dari Redux atau arsitektur yang dapat dikomposisi, tetapi tidak seperti kerangka kerja yang Anda tidak perlu khawatir tentang menambahkan tindakan atau peredam. Dengan implementasi Store ini, semua data Anda tetap ada untuk Anda secara otomatis, tidak diperlukan kode tambahan. Ini memungkinkan Anda untuk membangun aplikasi pembaruan realtime dengan dukungan offline penuh dengan cara yang sangat sederhana dan langsung.
Anda dapat membaca tinjauan level tinggi butik di bawah ini, tetapi butik juga sepenuhnya didokumentasikan di sini.
Kami akan melalui tinjauan tingkat tinggi dari Store di bawah ini, tetapi Store sepenuhnya didokumentasikan dengan konteks, kasus penggunaan, dan contoh di sini.
Seluruh area permukaan API untuk mencapai dukungan offline penuh dan pembaruan model realtime di seluruh aplikasi Anda adalah tiga metode, .insert() , .remove() , dan .removeAll() .
// Create a Store ¹
let store = Store < Animal > (
storage : SQLiteStorageEngine . default ( appendingPath : " Animals " ) ,
cacheIdentifier : . id
)
// Insert an item into the Store ²
let redPanda = Animal ( id : " red_panda " )
try await store . insert ( redPanda )
// Remove an animal from the Store
try await store . remove ( redPanda )
// Insert two more animals to the Store
let dog = Animal ( id : " dog " )
let cat = Animal ( id : " cat " )
try await store . insert ( [ dog , cat ] )
// You can read items directly
print ( store . items ) // Prints [dog, cat]
// You also don't have to worry about maintaining uniqueness, the Store handles uniqueness for you
let secondDog = Animal ( id : " dog " )
try await store . insert ( secondDog )
print ( store . items ) // Prints [dog, cat]
// Clear your store by removing all the items at once.
store . removeAll ( )
print ( store . items ) // Prints []
// You can even chain commands together
try await store
. insert ( dog )
. insert ( cat )
. run ( )
print ( store . items ) // Prints [dog, cat]
// This is a good way to clear stale cached data
try await store
. removeAll ( )
. insert ( redPanda )
. run ( )
print ( store . items ) // Prints [redPanda]Dan jika Anda sedang membangun aplikasi SwiftUi, Anda tidak perlu mengubah apa pun, butik dibuat untuk dan dengan Swiftui dalam pikiran. (Tapi tentu saja bekerja dengan baik di UIKIT dan APPKIT.)
// Since items is a @Published property
// you can subscribe to any changes in realtime.
store . $items . sink ( { items in
print ( " Items was updated " , items )
} )
// Works great with SwiftUI out the box for more complex pipelines.
. onReceive ( store . $items , perform : {
self . allItems = $0 . filter ( { $0 . id > 100 } )
} )¹ Anda dapat memiliki sebanyak atau sesedikit toko seperti yang Anda inginkan. Ini mungkin strategi yang baik untuk memiliki satu toko untuk semua gambar yang Anda unduh di aplikasi Anda, tetapi Anda mungkin juga ingin memiliki satu toko per tipe model yang ingin Anda cache. Anda bahkan dapat membuat toko terpisah untuk tes, butik tidak preskriptif dan pilihan untuk bagaimana Anda ingin memodelkan data Anda adalah milik Anda. Anda juga akan melihat, itu adalah konsep dari Bodega yang dapat Anda baca di dokumentasi StorageEngine Bodega.
² Di bawah kap toko melakukan pekerjaan menyimpan semua perubahan pada disk saat Anda menambahkan atau menghapus item.
³ Di SwiftUi Anda bahkan dapat memberi daya pada View Anda dengan $items dan menggunakan .onReceive() untuk memperbarui dan memanipulasi data yang diterbitkan oleh $items toko.
Peringatan menyimpan gambar atau data biner lainnya di Boutique secara teknis didukung tetapi tidak dianjurkan. Alasannya adalah bahwa menyimpan gambar di Boutique's Can Balloon di toko dalam memori, dan memori aplikasi Anda sebagai hasilnya. Untuk alasan yang sama karena tidak disarankan untuk menyimpan gambar atau gumpalan biner dalam database, tidak disarankan untuk menyimpan gambar atau gumpalan biner di butik.
Kami akan melalui tinjauan tingkat tinggi dari pembungkus properti @Stored di bawah ini, tetapi @Stored sepenuhnya didokumentasikan dengan konteks, kasus penggunaan, dan contoh di sini.
Itu mudah, tapi saya ingin menunjukkan sesuatu yang membuat butik terasa benar -benar ajaib. Store ini adalah cara sederhana untuk mendapatkan manfaat penyimpanan offline dan pembaruan realtime, tetapi dengan menggunakan pembungkus properti @Stored kita dapat men-cache properti apa pun dalam memori dan pada disk hanya dengan satu baris kode.
extension Store where Item == RemoteImage {
// Initialize a Store to save our images into
static let imagesStore = Store < RemoteImage > (
storage : SQLiteStorageEngine . default ( appendingPath : " Images " )
)
}
final class ImagesController : ObservableObject {
/// Creates a @Stored property to handle an in-memory and on-disk cache of images. ⁴
@ Stored ( in : . imagesStore ) var images
/// Fetches `RemoteImage` from the API, providing the user with a red panda if the request succeeds.
func fetchImage ( ) async throws -> RemoteImage {
// Hit the API that provides you a random image's metadata
let imageURL = URL ( string : " https://image.redpanda.club/random/json " ) !
let randomImageRequest = URLRequest ( url : imageURL )
let ( imageResponse , _ ) = try await URLSession . shared . data ( for : randomImageRequest )
return RemoteImage ( createdAt : . now , url : imageResponse . url , width : imageResponse . width , height : imageResponse . height , imageData : imageResponse . imageData )
}
/// Saves an image to the `Store` in memory and on disk.
func saveImage ( image : RemoteImage ) async throws {
try await self . $images . insert ( image )
}
/// Removes one image from the `Store` in memory and on disk.
func removeImage ( image : RemoteImage ) async throws {
try await self . $images . remove ( image )
}
/// Removes all of the images from the `Store` in memory and on disk.
func clearAllImages ( ) async throws {
try await self . $images . removeAll ( )
}
} Itu saja, itu benar -benar itu. Teknik ini berskala dengan sangat baik, dan berbagi data ini di banyak tampilan adalah persis bagaimana skala butik dari aplikasi sederhana hingga kompleks tanpa menambahkan kompleksitas API. Sulit dipercaya bahwa sekarang aplikasi Anda dapat memperbarui keadaannya secara real time dengan penyimpanan offline penuh berkat hanya satu baris kode. @Stored(in: .imagesStore) var images
⁴ (Jika Anda lebih suka memisahkan toko dari model tampilan, pengontrol, atau objek manajer Anda, Anda dapat menyuntikkan toko ke objek seperti ini.)
final class ImagesController : ObservableObject {
@ Stored var images : [ RemoteImage ]
init ( store : Store < RemoteImage > ) {
self . _images = Stored ( in : store )
}
} Kami akan melalui ikhtisar tingkat tinggi dari @StoredValue dan @SecurelyStoredValue Properti Wrappers di bawah ini, tetapi mereka sepenuhnya didokumentasikan dengan konteks, kasus penggunaan, dan contoh di sini.
Store dan @Stored dibuat untuk menyimpan berbagai data karena sebagian besar aplikasi data render datang dalam bentuk array. Tetapi kadang -kadang kita perlu menyimpan nilai individu, di situlah @StoredValue dan @SecurelyStoredValue berguna.
Apakah Anda perlu menyimpan informasi penting untuk waktu berikutnya aplikasi Anda diluncurkan, menyimpan token auth di gantungan kunci, atau Anda ingin mengubah bagaimana aplikasi terlihat berdasarkan pengaturan pengguna, konfigurasi aplikasi tersebut adalah nilai individual yang ingin Anda persembahkan.
Sering kali orang akan memilih untuk menyimpan item individual seperti itu di UserDefaults . Jika Anda menggunakan @AppStorage maka @StoredValue akan terasa seperti di rumah, ia memiliki API yang sangat mirip dengan beberapa fitur tambahan. A @StoredValue akan berakhir disimpan di UserDefaults , tetapi juga memperlihatkan publisher sehingga Anda dapat dengan mudah berlangganan perubahan.
// Setup a `@StoredValue has the same API.
@ StoredValue ( key : " hasHapticsEnabled " )
var hasHapticsEnabled = false
// You can also store nil values
@ StoredValue ( key : " lastOpenedDate " )
var lastOpenedDate : Date ? = nil
// Enums work as well, as long as it conforms to `Codable` and `Equatable`.
@ StoredValue ( key : " currentTheme " )
var currentlySelectedTheme = . light
// Complex objects work as well
struct UserPreferences : Codable , Equatable {
var hasHapticsEnabled : Bool
var prefersDarkMode : Bool
var prefersWideScreen : Bool
var spatialAudioEnabled : Bool
}
@ StoredValue ( key : " userPreferences " )
var preferences = UserPreferences ( )
// Set the lastOpenedDate to now
$lastOpenedDate . set ( . now )
// currentlySelected is now .dark
$currentlySelectedTheme . set ( . dark )
// StoredValues that are backed by a boolean also have a toggle() function
$hasHapticsEnabled . toggle ( ) Pembungkus properti @SecurelyStoredValue dapat melakukan semua yang dilakukan @StoredValue , tetapi alih -alih menyimpan nilai di UserDefaults a @SecurelyStoredValue akan bertahan dalam item di gantungan kunci sistem. Ini sangat cocok untuk menyimpan nilai sensitif seperti kata sandi atau token auth, yang tidak ingin Anda simpan di UserDefaults .
Jika Anda memiliki pertanyaan, saya akan meminta Anda melihat dokumentasi terlebih dahulu, baik Boutique dan Bodega sangat terdokumentasi. Di atas butik itu hadir dengan bukan hanya satu tetapi dua aplikasi demo, masing-masing melayani tujuan yang berbeda tetapi menunjukkan bagaimana Anda dapat membangun aplikasi yang didukung butik.
Ketika saya sedang membangun V1, saya perhatikan bahwa orang -orang yang mendapat butik menyukainya, dan orang -orang yang berpikir itu mungkin baik tetapi memiliki pertanyaan tumbuh untuk menyukainya begitu mereka mengerti bagaimana menggunakannya. Karena itu saya mencari untuk menulis banyak dokumentasi yang menjelaskan konsep dan kasus penggunaan umum yang akan Anda temui saat membangun aplikasi iOS atau macOS. Jika Anda masih memiliki pertanyaan atau saran, saya sangat terbuka untuk umpan balik, bagaimana berkontribusi dibahas di bagian umpan balik yang tepat dari readme ini.
Boutique sangat berguna sendiri untuk membangun aplikasi ready-ready offline dengan hanya beberapa baris kode, tetapi bahkan lebih kuat ketika Anda menggunakan arsitektur toko pengontrol tampilan model yang telah saya kembangkan, tunjukkan dalam ImagesController di atas. MVC menyatukan keakraban dan kesederhanaan arsitektur MVC yang Anda kenal dan cintai dengan kekuatan Store , untuk memberikan aplikasi Anda manajemen negara dan arsitektur data yang sederhana namun terdefinisi dengan baik.
Jika Anda ingin mempelajari lebih lanjut tentang cara kerjanya, Anda dapat membaca tentang filosofi dalam posting blog tempat saya menjelajahi MVC untuk SwiftUi, dan Anda dapat menemukan implementasi referensi dari aplikasi MVCS realtime yang siap-offline yang ditenagai oleh butik dalam repo ini.
Kami hanya menggaruk permukaan apa yang bisa dilakukan butik di sini. Memanfaatkan Bodega's StorageEngine Anda dapat membangun jalur pipa data kompleks yang melakukan segalanya mulai dari caching data hingga berinteraksi dengan server API Anda. Boutique dan Bodega lebih dari perpustakaan, mereka adalah satu set primitif untuk aplikasi berbasis data, jadi saya sarankan memberi mereka kesempatan, bermain dengan aplikasi demo, dan bahkan membangun aplikasi Anda sendiri!
Proyek ini menyediakan berbagai bentuk memberikan umpan balik kepada pengelola.
Jika Anda memiliki pertanyaan tentang Boutique, kami meminta Anda berkonsultasi pertama kali untuk melihat apakah pertanyaan Anda telah dijawab di sana.
Proyek ini banyak didokumentasikan tetapi juga mencakup beberapa proyek sampel.
StorageEngine khusus, proyek ini akan melayani Anda dengan cara untuk menguji kinerja operasi yang perlu Anda bangun.Jika Anda masih memiliki pertanyaan, peningkatan, atau cara untuk meningkatkan butik, proyek ini memanfaatkan fitur diskusi GitHub.
Jika Anda menemukan bug dan ingin melaporkan masalah akan dihargai.
Swift Package Manager adalah alat untuk mengotomatisasi distribusi kode Swift dan diintegrasikan ke dalam sistem pembuatan Swift.
Setelah Anda mengatur paket Swift, menambahkan butik sebagai ketergantungan semudah menambahkannya ke nilai dependensi Package.swift Anda.
dependencies: [
. package ( url : " https://github.com/mergesort/Boutique.git " , . upToNextMajor ( from : " 1.0.0 " ) )
] Jika Anda lebih suka tidak menggunakan SPM, Anda dapat mengintegrasikan butik ke dalam proyek Anda secara manual dengan menyalin file.
Hai, saya Joe di mana -mana di web, tetapi terutama di Mastodon.
Lihat lisensi untuk informasi lebih lanjut tentang bagaimana Anda dapat menggunakan butik.
Boutique adalah tenaga cinta untuk membantu pengembang membangun aplikasi yang lebih baik, membuatnya lebih mudah bagi Anda untuk membuka kreativitas Anda dan membuat sesuatu yang luar biasa untuk diri sendiri dan pengguna Anda. Jika Anda menganggap butik berharga, saya akan sangat menghargainya jika Anda mempertimbangkan untuk membantu mensponsori pekerjaan open source saya, sehingga saya dapat terus mengerjakan proyek -proyek seperti Boutique untuk membantu pengembang seperti Anda.
Sekarang Anda tahu apa yang ada di toko untuk Anda, saatnya untuk memulai ?