
"Ich habe Kerndaten herausgerissen, so sollte sie funktionieren"
- Josh Holtz
"Boutique ist lächerlich einfach zu implementieren und macht Beharrlichkeit zum Kinderspiel. Es ist mein erster Ergänzung zu jedem Projekt, das ich anfange.
- Tyler Hillsman
"Die Boutique ist von unschätzbarem Wert geworden, ich benutze es jetzt in jedem Seitenprojekt. Es ist großartig und die Kosten für den Einstieg für den Einstieg sind praktisch null."
- Romain Pouclet
Wenn Sie Boutique wertvoll finden, würde ich es sehr schätzen, wenn Sie in Betracht ziehen würden, meine Open -Source -Arbeit zu sponsern, damit ich weiterhin an Projekten wie Boutique arbeiten kann, um Entwicklern wie Sie zu helfen.
Boutique ist eine einfache, aber leistungsstarke Persistenzbibliothek, eine kleine Reihe von Immobilienverpackungen und -typen, die es ermöglichen, unglaublich einfache staatlich gesteuerte Apps für Swiftui, Uikit und Appkit zu erstellen. Mit seiner doppelt bewegten Speicher + Festplatte Caching Architecture Boutique bietet Boutique eine Möglichkeit, Apps zu erstellen, die in Echtzeit mit vollständigem Offline-Speicher in nur wenigen Codezeilen mit einer unglaublich einfachen API aktualisieren. Boutique ist auf Bodega gebaut, und Sie finden eine Demo-App, die auf der Model View Controller Store-Architektur in diesem Repo erstellt wurde, die Ihnen zeigt, wie Sie eine Swiftui-App von Offline-Bereitschaft in nur wenigen Codezeilen erstellen. Sie können mehr über das Denken hinter der Architektur in diesem Blog -Beitrag erfahren, in dem die MVCS -Architektur erforscht wird.
Boutique hat nur ein Konzept, das Sie verstehen müssen. Wenn Sie Daten im Store speichern, werden Ihre Daten automatisch für Sie bestehen und als reguläres Swift -Array freigelegt. Die @StoredValue und @SecurelyStoredValue -Immobilienverpackungen funktionieren genauso, aber anstelle eines Arrays arbeiten sie mit singulären Swift -Werten. Sie müssen nie über Datenbanken nachdenken, alles in Ihrer App ist ein regelmäßiges Swift -Array oder -wert, das die Modelle Ihrer App verwendet, mit einfachem Code, der wie jede andere App aussieht.
Möglicherweise sind Sie mit dem Store von Redux oder der komponierbaren Architektur vertraut, aber im Gegensatz zu diesen Frameworks müssen Sie sich jedoch keine Sorgen über das Hinzufügen von Aktionen oder Reduzierern machen. Mit dieser Store werden alle Ihre Daten automatisch für Sie bestehen, ohne zusätzlichen Code erforderlich. Auf diese Weise können Sie Echtzeit -Aktualisierungs -Apps mit vollständiger Offline -Unterstützung auf unglaublich einfache und unkomplizierte Weise erstellen.
Sie können einen hohen Überblick über die Boutique unten lesen, aber auch die Boutique ist hier vollständig dokumentiert.
Wir werden einen Überblick über den unten stehenden Store unten durchlaufen, aber der Store ist hier vollständig mit Kontext, Anwendungsfällen und Beispielen dokumentiert.
Die gesamte Oberfläche der API zur Erreichung der vollständigen Offline -Unterstützung und in Echtzeitmodellaktualisierungen in Ihrer gesamten App ist drei Methoden, .insert() , .remove() und .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]Und wenn Sie eine Swiftui -App bauen, müssen Sie nichts ändern, für die Boutique wurde für und mit Swiftui im Sinn gemacht. (Funktioniert aber natürlich gut in Uikit und 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 } )
} )¹ Sie können so viele oder so wenige Geschäfte haben, wie Sie möchten. Es kann eine gute Strategie sein, einen Speicher für alle Bilder zu haben, die Sie in Ihrer App herunterladen. Möglicherweise möchten Sie auch einen Speicher pro Modell-Typ haben, den Sie möchten. Sie können sogar separate Geschäfte für Tests erstellen, Boutique ist nicht vorschreibend und die Wahl, wie Sie Ihre Daten modellieren möchten, gehört Ihnen. Sie werden auch bemerken, dass dies ein Konzept von Bodega ist, über das Sie in den Dokumentation von Bodega in StoresEngine lesen können.
² Unter der Motorhaube wird das Geschäft ausgeführt, wenn Sie alle Änderungen auf der Festplatte sparen, wenn Sie Artikel hinzufügen oder entfernen.
³ In Swiftui können Sie Ihre View sogar mit $items einschalten und .onReceive() verwenden, um Daten zu aktualisieren und zu manipulieren, die von den $items des Geschäfts veröffentlicht werden.
Warnspeicherbilder oder andere binäre Daten in Boutique werden technisch unterstützt, aber nicht empfohlen. Der Grund dafür ist, dass das Speichern von Bildern in Boutique den In-Memory-Store und den Speicher Ihrer App dadurch auflagern kann. Aus ähnlichen Gründen, wie es nicht empfohlen wird, Bilder oder binäre Blobs in einer Datenbank zu speichern, wird nicht empfohlen, Bilder oder binäre Blobs in Boutique zu speichern.
Wir werden einen Überblick über die @Stored -Eigenschaftswrapper unten durchlaufen, aber @Stored ist hier vollständig mit Kontext, Anwendungsfällen und Beispielen dokumentiert.
Das war einfach, aber ich möchte Ihnen etwas zeigen, das sich Boutique geradezu magisch anfühlt. Der Store ist eine einfache Möglichkeit, die Vorteile von Offline-Speicher- und Echtzeit-Updates zu nutzen. Durch die Verwendung des @Stored Immobilien-Wrappers können wir jede Eigenschaft in Memory und auf der Festplatte mit nur einer Codezeile zwischenspeichern.
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 ( )
}
} Das ist es, das ist es wirklich. Diese Technik skaliert sehr gut, und diese Daten über viele Ansichten hinweg zu teilen, ist genau so, wie Boutique von einfachen zu komplexen Apps ohne Hinzufügen von API -Komplexität skaliert wird. Es ist kaum zu glauben, dass Ihre App jetzt ihren Status in Echtzeit mit vollem Offline -Speicher dank einer Codezeile aktualisieren kann. @Stored(in: .imagesStore) var images
⁴ (Wenn Sie es vorziehen möchten, den Speicher aus Ihrem Ansichtsmodell, Controller oder Manager -Objekt zu entkoppeln, können Sie Geschäfte wie dieses in das Objekt injizieren.)
final class ImagesController : ObservableObject {
@ Stored var images : [ RemoteImage ]
init ( store : Store < RemoteImage > ) {
self . _images = Stored ( in : store )
}
} Wir werden unten einen Überblick über die @StoredValue und @SecurelyStoredValue -Wrapper durchliegen.
Der Store und @Stored wurden erstellt, um eine Array von Daten zu speichern, da die meisten Daten -Apps in Form eines Arrays erfolgen. @StoredValue gelegentlich müssen wir @SecurelyStoredValue individuellen Wert speichern.
Unabhängig davon, ob Sie eine wichtige Informationen zum nächsten Start Ihrer App speichern müssen, ein Auth -Token in der Schlüsselbund gespeichert oder die Aussehen einer App basierend auf den Einstellungen eines Benutzers ändern möchten, sind diese App -Konfigurationen individuelle Werte, die Sie bestehen bleiben möchten.
Oft entscheiden sich die Leute, einzelne Artikel wie diese in UserDefaults zu speichern. Wenn Sie @AppStorage verwendet haben, wird @StoredValue sich wie zu Hause anfühlen. Es hat eine sehr ähnliche API mit einigen zusätzlichen Funktionen. Ein @StoredValue wird am Ende in UserDefaults gespeichert, enthält jedoch auch einen publisher , sodass Sie sich leicht Änderungen abonnieren können.
// 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 ( ) Der @SecurelyStoredValue -Eigenschaftswrapper kann alles tun, was ein @StoredValue tut, aber anstatt Werte in UserDefaults zu speichern, bleibt ein @SecurelyStoredValue die Elemente in der Schlüsselbund des Systems bestehen. Dies ist perfekt zum Speichern sensibler Werte wie Passwörter oder Auth -Token, die Sie nicht in UserDefaults speichern möchten.
Wenn Sie Fragen haben, würde ich Ihnen bitte die Dokumentation zuerst ansehen, sowohl Boutique als auch Bodega sind sehr stark dokumentiert. Darüber hinaus wird nur eine, sondern zwei Demo-Apps geliefert, die jeweils einen anderen Zweck erfüllen, aber zeigen, wie Sie eine von Boutique unterstützte App erstellen können.
Als ich V1 baute, bemerkte ich, dass Menschen, die Boutique bekamen, es liebten, und Leute, die es für gut dachten, es sei gut, liebte es, es zu lieben, als sie verstanden, wie man es benutzt. Aus diesem Grund habe ich gesucht, eine Menge Dokumentation zu schreiben, in denen die Konzepte und gemeinsamen Anwendungsfälle erläutert werden, denen Sie beim Erstellen einer iOS- oder macOS -App begegnen werden. Wenn Sie immer noch Fragen oder Vorschläge haben, bin ich sehr offen für Feedback, wie man einen Beitrag leisten kann, wird im treffend benannten Feedback -Abschnitt dieses ReadMe erörtert.
Boutique ist für sich genommen sehr nützlich, um Echtzeit-Offline-Apps mit nur wenigen Codezeilen zu erstellen, aber es ist noch leistungsfähiger, wenn Sie die von mir entwickelte Model View Controller-Store-Architektur verwenden, die im obigen ImagesController demonstriert ist. MVCS vereint die Vertrautheit und Einfachheit der MVC-Architektur, die Sie mit der Kraft eines Store kennen und lieben, um Ihrer App ein einfaches, aber genau definiertes staatliches Management und Datenarchitektur zu geben.
Wenn Sie mehr darüber erfahren möchten, wie es funktioniert, können Sie in einem Blog-Beitrag über die Philosophie lesen, in der ich MVCs für Swiftui erforsche, und Sie können eine Referenzimplementierung einer offline-fähigen Echtzeit-MVCS-App finden, die von Boutique in diesem Repo betrieben wird.
Wir haben nur die Oberfläche dessen zerkratzt, was Boutique hier tun kann. Nutzung von Bodegas StorageEngine Sie können komplexe Datenpipelines erstellen, die alles von Caching -Daten bis hin zur Schnittstelle mit Ihrem API -Server erstellen. Boutique und Bodega sind mehr als Bibliotheken, sie sind eine Reihe von Primitiven für jede datengesteuerte Anwendung. Ich schlage daher vor, ihnen eine Aufnahme zu geben, mit der Demo-App zu spielen und sogar eine eigene App zu erstellen!
Dieses Projekt bietet mehrere Formen der Bereitstellung von Feedback an die Betreuer.
Wenn Sie eine Frage zu Boutique haben, stellen wir Ihnen zuerst die Dokumentation an, um festzustellen, ob Ihre Frage dort beantwortet wurde.
Dieses Projekt ist stark dokumentiert, enthält jedoch auch mehrere Beispielprojekte.
StorageEngine arbeiten, bietet Ihnen dieses Projekt eine Möglichkeit, die Leistung der Vorgänge zu testen, die Sie erstellen müssen.Wenn Sie noch eine Frage, eine Verbesserung oder eine Möglichkeit zur Verbesserung der Boutique haben, nutzt dieses Projekt die Diskussionsfunktionen von Github.
Wenn Sie einen Fehler finden und ein Problem melden möchten, wäre dies geschätzt.
Der Swift -Paket -Manager ist ein Tool zur Automatisierung der Verteilung des Swift -Codes und ist in das Swift -Build -System integriert.
Sobald Sie Ihr Swift -Paket eingerichtet haben, ist das Hinzufügen von Boutique als Abhängigkeit so einfach wie das Hinzufügen zum Abhängigkeitswert Ihres Package.swift .
dependencies: [
. package ( url : " https://github.com/mergesort/Boutique.git " , . upToNextMajor ( from : " 1.0.0 " ) )
] Wenn Sie es vorziehen, SPM nicht zu verwenden, können Sie die Boutique manuell in Ihr Projekt integrieren, indem Sie die Dateien einkopieren.
Hallo, ich bin überall im Internet, aber besonders auf Mastodon.
Weitere Informationen zur Verwendung von Boutique finden Sie in der Lizenz.
Boutique ist eine Liebesarbeit, um Entwicklern zu helfen, bessere Apps aufzubauen, und es Ihnen leichter erleichtert, Ihre Kreativität freizuschalten und für Sie und Ihre Benutzer etwas Erstaunliches zu machen. Wenn Sie Boutique wertvoll finden, würde ich es sehr schätzen, wenn Sie in Betracht ziehen würden, meine Open -Source -Arbeit zu sponsern, damit ich weiterhin an Projekten wie Boutique arbeiten kann, um Entwicklern wie Sie zu helfen.
Jetzt, wo Sie wissen, was für Sie auf Lager ist, ist es Zeit, loszulegen ?