Echtzeit ist ORM -Framework, das die Erstellung komplexer Datenbankstrukturen einfach macht.
Einfache skalierbare Modellstruktur
Dateien
Sammlungen
Referenzen
UI, Form
Die Firebase Echtzeitdatenbank wird vollständig unterstützt und verwendet in der Produktion. Wenn Sie Clean Firebase API verwenden, kann Echtzeit dazu beitragen, App schneller zu erstellen, um komplexe Strukturen zum Speichern von Daten anzuwenden, um die Benutzeroberfläche mit reaktiven Verhaltensweisen zu aktualisieren. Echtzeit bietet leichten Datenverkehr, faule Initialisierung von Daten und eine gute Datenverteilung.
FoundationDB wird unterstützt, aber mit einigen Einschränkungen, da FDB keine nativen Beobachtungsmechanismen hat.
In AppDelegate in func application(_:didFinishLaunchingWithOptions:) Sie müssen unten Code anrufen, um die Arbeitsumgebung zu konfigurieren. Für die Cache -Richtlinie ist nun gültiger Werte case .noCache, .persistance nur. Cache im Speicher wird noch nicht implementiert.
func application ( _ application : UIApplication , didFinishLaunchingWithOptions launchOptions : [ UIApplicationLaunchOptionsKey : Any ] ? ) -> Bool {
/// ...
/// initialize Realtime
RealtimeApp . initialize ( ... )
///...
return true
} So erstellen Sie jede Modelldatenstruktur, die Sie durch Object erstellen können. Sie können Kindereigenschaften mit Klassen definieren:
Object ;ReadonlyProperty , Property , Reference , Relation , ReadonlyFile , File ;References , Values , AssociatedValues und so weiter; Wenn Sie faule Eigenschaften verwenden, müssen Sie die Klassenfunktion lazyPropertyKeyPath(for:) implementieren. (Bitte sagen Sie mir, ob Sie wissen, wie es vermeiden, ohne NSObject zu erben). Diese Funktion wurde für jede Unterklasse erfolgt, daher benötigen Sie keine Aufruf -Super -Implementierung. Beispiel: class User : Object {
lazy var name : Property < String > = " name " . property ( in : self )
lazy var age : Property < Int > = " age " . property ( in : self )
lazy var photo : File < UIImage ? > = " photo " . file ( in : self , representer : . png )
lazy var groups : References < RealtimeGroup > = " groups " . references ( in : self , elements : . groups )
lazy var scheduledConversations : Values < Conversation > = " scheduledConversations " . values ( in : self )
lazy var ownedGroup : Relation < RealtimeGroup ? > = " ownedGroup " . relation ( in : self , " manager " )
override class func lazyPropertyKeyPath ( for label : String ) -> AnyKeyPath ? {
switch label {
case " name " : return User . name
case " age " : return User . age
case " photo " : return User . photo
case " groups " : return User . groups
case " ownedGroup " : return User . ownedGroup
case " scheduledConversations " : return User . scheduledConversations
default : return nil
}
}
}
let user = User ( in : Node ( key : " user_1 " ) )
user . name <== " User name "
user . photo <== UIImage ( named : " img " )
let transaction = user . save ( in : . root )
transaction . commit ( with : { state , err in
/// process error
} )ReadOrlyproperty - Readonly gespeicherte Eigenschaft für einen beliebigen Wert.
Eigenschaft - gespeicherte Eigenschaft für einen beliebigen Wert.
Referenz - Speichert die Referenz auf einen beliebigen Datenbankwert. Impliziert keine referenzielle Integrität. Verwenden Sie es, wenn der Datensatz nicht entfernt wird oder ein anderer Grund, der keine referenzielle Integrität benötigt.
Relation - speichert Referenz zu einem Datenbankwert.
ReadonLyFile - Readonly -gelagertes Eigenschaft für Datei in Firebase Storage.
Datei - gespeicherte Eigenschaft für die Datei im Firebase Storage.
Alle Eigenschaften übernehmen eine @propertyWrapper -Funktion, aber während Swift in benutzerdefinierten faulen Eigenschaften nicht unterstützt zu self zu sichern, definieren Sie die Eigenschaften im Allgemeinen nutzlos.
class Some : Object {
lazy var array : Values < Object > = " some_array " . values ( in : self )
lazy var references : References < Object > = " some_linked_array " . references ( in : self , elements : . linkedObjects )
lazy var dictionary : AssociatedValues < Object > = " some_dictionary " . dictionary ( in : self , keys : . keyObjects )
} Einige veränderliche Operationen von Sammlungen können isSynced State erfordern. Um diesen Zustand zu erreichen, verwenden Sie Funktionen func runObserving() oder festgelegtes Eigentum keepSynced: Bool to true .
(Verteilte) Referenzen sind Array, das Objekte als Referenzen speichert. Quellelemente müssen in derselben Referenz lokalisieren. Bei der Einführung des Objekts in dieses Array erstellt das Link zum Seitenobjekt.
(Explizite) Werte sind ein Array, das Objekte nach Wert an sich selbst speichert. Das Präfix von 'explizitem' wird in der Sammlung verwendet, die Elemente ohne Sammelansicht speichert.
References , Values mutieren:
do {
let transaction = Transaction ( )
...
let element = Element ( )
try array . write ( element : element , in : transaction )
try otherArray . remove ( at : 1 , in : trasaction )
transaction . commit { ( err ) in
// process error
self . tableView . reloadData ( )
}
} catch let e {
// process error
}(Explizit) AssociatedValues ist ein Wörterbuch, bei dem Schlüssel Referenzen sind, Werte jedoch Objekte. Wenn Sie den Wert speichern, erstellt der Link zum Seitenschlüsselobjekt.
AssociatedValues Mutation:
do {
let transaction = Transaction ( )
...
let element = Element ( )
try dictionary . write ( element : element , key : key , in : transaction )
try otherDictionary . remove ( by : key , in : transaction )
transaction . commit { ( err ) in
// process error
}
} catch let e {
// process error
}MapRealTimeCollection ist eine unveränderliche Sammlung, die Elemente aus der Kartenfunktion erhält. Dies ist das Ergebnis von X.lazyMap (_ Transformation :) Methode, wobei x jede RealTimeCollection ist.
let userNames = Values < User > ( in : usersNode ) . lazyMap { user in
return user . name
}<== - Zuweisungsoperator. Kann (oder abrufen) Wert an (von) jeder Echtzeiteigenschaft zuweisen (oder abzurufen).==== ,! !=== - Vergleichsoperatoren. Kann verwenden, um alle Echtzeiteigenschaften zu vergleichen, bei denen ihre Werte einem Equatable Protokoll entsprechen.?? - Infix-Operator, der einen Null-Koalescing-Vorgang durchführt, der den verpackten Wert einer Echtzeiteigenschaft oder einen Standardwert zurückgibt.<- - Präfixbetreiber. Kann zum Konvertieren der Instanz des Closure, Assign .Transaktion - Objekt, das alle Informationen zu Schreibtransaktionen enthält. Fast alle Datenänderungen werden mit diesem Objekt durchgeführt. Die veränderlichsten Operationen nehmen die Transaktion einfach als Parameter an, aber um benutzerdefinierte komplexe Operationen zu erstellen, können Sie diese Methoden verwenden:
/// adds operation of save RealtimeValue as single value as is
func set < T > ( _ value : T , by node : Node ) where T : RealtimeValue & RealtimeValueEvents
/// adds operation of delete RealtimeValue
func delete < T > ( _ value : T ) where T : RealtimeValue & RealtimeValueEvents
/// adds operation of update RealtimeValue
func update < T > ( _ value : T ) where T : ChangeableRealtimeValue & RealtimeValueEvents & Reverting
/// method to merge actions of other transaction
func merge ( _ other : Transaction )Weitere Informationen finden Sie unter Beispielprojekt.
SinglesectionTableViewDelegate - Bietet eine einzelne Abschnittsdatenquelle für UitableView mit automatischer Aktualisierung. AbschnittedTableViewDelegate - Bietet eine geschnittene Datenquelle für UitableView mit automatischer Aktualisierung. CollectionViewDelegate - Bietet Datenquelle für UICollectionView mit automatischer Aktualisierung.
delegate . register ( UITableViewCell . self ) { ( item , cell , user , ip ) in
item . bind (
user . name , { cell , name in
cell . textLabel ? . text = name
} ,
{ err in
print ( err )
}
)
}
delegate . bind ( tableView )
delegate . tableDelegate = self
// data
users . changes
. listening (
onValue : { [ weak tableView ] ( e ) in
guard let tv = tableView else { return }
switch e {
case . initial : tv . reloadData ( )
case . updated ( let deleted , let inserted , let modified , let moved ) :
tv . beginUpdates ( )
tv . insertRows ( at : inserted . map ( { IndexPath ( row : $0 , section : 0 ) } ) , with : . automatic )
tv . deleteRows ( at : deleted . map ( { IndexPath ( row : $0 , section : 0 ) } ) , with : . automatic )
tv . reloadRows ( at : modified . map ( { IndexPath ( row : $0 , section : 0 ) } ) , with : . automatic )
moved . forEach { from , to in
tv . moveRow ( at : IndexPath ( row : from , section : 0 ) , to : IndexPath ( row : to , section : 0 ) )
}
tv . endUpdates ( )
}
} ,
onError : onError
)
. add ( to : listeningCollector ) Erhältlich als getrenntes Modul mit Combine .
class User : Object {
var name : Property < String >
var age : Property < Int >
}
class FormViewController : UIViewController {
var form : Form < User >
override func viewDidLoad ( ) {
super . viewDidLoad ( )
let name = Row < TextCell , Model > . inputRow (
" input " ,
title : Localized . name ,
keyboard : . name ,
placeholder : . inputPlaceholder ( Localized . name ) ,
onText : { $0 . name <== $1 }
)
name . onUpdate { ( args , row ) in
args . view . textField . text <== args . model . name
}
let age = Row < TextCell , Model > . inputRow (
" input " ,
title : Localized . age ,
keyboard : . numberPad ,
placeholder : requiredPlaceholder ,
onText : { $0 . age <== $1 }
)
age . onUpdate { ( args , row ) in
args . view . textField . text <== args . model . age
}
let button : Row < ButtonCell , Model > = Row ( reuseIdentifier : " button " )
button . onUpdate { ( args , row ) in
args . view . titleLabel . text = Localized . login
}
button . onSelect { [ unowned self ] ( _ , row ) in
self . submit ( )
}
let fieldsSection : StaticSection < Model > = StaticSection ( headerTitle : nil , footerTitle : nil )
fieldsSection . addRow ( name )
fieldsSection . addRow ( age )
let buttonSection : StaticSection < Model > = StaticSection ( headerTitle : nil , footerTitle : nil )
buttonSection . addRow ( button )
form = Form ( model : User ( ) , sections : [ fieldsSection , buttonSection ] )
form . tableView = tableView
form . tableDelegate = self
}
}Um Änderungen auf lokaler Ebene zu empfangen, verwenden Sie Objekte, die dieses Protokoll entsprechen. Es hat eine ähnliche RXSwift -Schnittstelle.
public protocol Listenable {
associatedtype OutData
/// Disposable listening of value
func listening ( _ assign : Assign < OutData > ) -> Disposable
}Fügen Sie das Debug -Argument "realtime_crash_on_error" hinzu, um interne Fehler zu erfassen.
Existiert auch das NodeJS -Modul, das für die VUE.JS -Anwendung erstellt wurde. Quellcode, den Sie im js -Ordner finden können.
Echtzeitobjekte sollten nicht zwischen Threads übergeben.
Um das Beispielprojekt auszuführen, klonen Sie das Repo und führen Sie zuerst pod install aus dem Beispielverzeichnis aus.
Xcode 9+, Swift 4.1+.
Swiftpm
. package ( url : " https://github.com/k-o-d-e-n/realtime.git " , . branch ( " master " ) )Echtzeit ist über Cocoapods erhältlich. Um es zu installieren, fügen Sie einfach die folgende Zeile zu Ihrem Podfile hinzu:
pod 'Realtime' pod 'RealtimeForm/Combine' , :git => 'https://github.com/k-o-d-e-n/Realtime.git' , :branch => 'master' Koryttsev Denis, [email protected]
Twitter: @k_o_d_e_n
Echtzeit ist im Rahmen der MIT -Lizenz verfügbar. Weitere Informationen finden Sie in der Lizenzdatei.