Le framework ORM est réel qui rend la création de structures de base de données complexes simples.
Structure du modèle évolutif simple
Fichiers
Collections
Références
Ui, forme
La base de données de Firebase en temps réel est entièrement prise en charge et utilise en production. Si vous utilisez une API Clean Firebase, le temps réel peut aider à créer une application plus rapidement, ici pour appliquer des structures complexes pour stocker des données, pour mettre à jour l'interface utilisateur à l'aide de comportements réactifs. Le temps réel fournit un trafic de données léger, une initialisation paresseuse des données, une bonne distribution des données.
FoundationDB est soutenue, mais avec certaines limites, car FDB n'a pas de mécanismes d'observation natifs.
Dans AppDelegate dans func application(_:didFinishLaunchingWithOptions:) Vous devez appeler le code ci-dessous, pour configurer l'environnement de travail. Maintenant, pour la politique de cache est case .noCache, .persistance uniquement. Le cache en mémoire n'est pas encore implémenté.
func application ( _ application : UIApplication , didFinishLaunchingWithOptions launchOptions : [ UIApplicationLaunchOptionsKey : Any ] ? ) -> Bool {
/// ...
/// initialize Realtime
RealtimeApp . initialize ( ... )
///...
return true
} Pour créer n'importe quelle structure de données de modèle que vous pouvez fabriquer en sous-classement Object . Vous pouvez définir les propriétés enfants en utilisant des classes:
Object ;ReadonlyProperty , Property , Reference , Relation , ReadonlyFile , File ;References , Values , AssociatedValues , etc. Si vous utilisez des propriétés paresseuses, vous devez implémenter la fonction de classe lazyPropertyKeyPath(for:) . (Veuillez me dire si vous savez comment l'évitez, sans hériter de NSObject). Cette fonction prévoyait chaque sous-classe, vous n'avez donc pas besoin d'appeler Super Implémentation. Exemple: 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
} )ReadOnlyProperty - Propriété stockée en lecture pour toute valeur.
Propriété - propriété stockée pour toute valeur.
Référence - Stores Reference sur n'importe quelle valeur de base de données. N'implique pas l'intégrité référentielle. Utilisez-le si l'enregistrement ne sera pas supprimé ou autre raison qui n'a pas besoin d'intégrité référentielle.
Relation - Stocke la référence sur toute valeur de base de données.
ReadOnlyFile - propriété stockée en lecture pour le fichier dans le stockage de la base de feu.
Fichier - propriété stockée pour le fichier dans le stockage de la base de feu.
Toutes les propriétés adoptent la fonctionnalité @propertyWrapper , mais bien que Swift soit un accès non étayé à self dans les propriétés paresseuses personnalisées, cette façon de définir les propriétés généralement inutiles.
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 )
} Certaines opérations mutables des collections peuvent nécessiter un état isSynced . Pour atteindre cet état, utilisez func runObserving() Fonction ou Set Property keepSynced: Bool to true .
(Distribué) Les références sont un tableau qui stocke les objets comme références. Les éléments de source doivent se localiser dans la même référence. Sur l'insertion de l'objet à ce tableau crée un lien sur l'objet latéral.
Les valeurs (explicites) sont le tableau qui stocke les objets par valeur en soi. Le préfixe «explicite» est utilisé dans la collection qui stocke les éléments sans vue de collection.
References , Values mutilant:
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
}(Explicite) AssociatedValues est le dictionnaire où les clés sont des références, mais les valeurs sont des objets. Sur la valeur de sauvegarde crée un lien sur l'objet de clé latérale.
AssociatedValues Mutating:
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 est une collection immuable qui obtient des éléments de la fonction MAP. Ceci est le résultat de la méthode x.lazymap (_ transform :) où x est n'importe quelle réalitétimeCollection.
let userNames = Values < User > ( in : usersNode ) . lazyMap { user in
return user . name
}<== - opérateur d'affectation. Peut utiliser pour attribuer (ou récupérer) la valeur à (à partir de) toute propriété en temps réel.==== , !=== - Opérateurs de comparaison. Peut utiliser pour comparer toutes les propriétés en temps réel où leurs valeurs sont conformes au protocole Equatable .?? - Infix Operator, qui effectue une opération de coalescing Nil, renvoyant la valeur enveloppée d'une propriété en temps réel ou d'une valeur par défaut.<- - Opérateur de préfixe. Peut utiliser pour convertir l'instance de Closure, Assign des types à une fermeture explicite ou à l'arrière.Transaction - Objet qui contient toutes les informations sur les transactions d'écriture. Presque tous les changements de données fonctionnent en utilisant cet objet. Les opérations les plus mutables prennent simplement la transaction en tant que paramètre, mais pour créer des opérations complexes personnalisées, vous pouvez utiliser ces méthodes:
/// 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 )Pour plus de détails, voir l'exemple de projet.
SingleSectionTableViewDelegate - fournit une source de données à section unique pour UableTView avec mise à jour automatique. SectionEdTableViewDelegate - Fournit une source de données sectionnée pour UableTView avec la mise à jour automatique. CollectionViewDelegate - Fournit une source de données pour UICOllectionView avec la mise à jour automatique.
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 ) Disponible en tant que module séparé avec le support 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
}
}Pour recevoir des modifications au niveau local, utilisez des objets conformes à ce protocole. Il a une interface RXSWift similaire.
public protocol Listenable {
associatedtype OutData
/// Disposable listening of value
func listening ( _ assign : Assign < OutData > ) -> Disposable
}Ajouter un argument de débogage 'réel_crash_on_error' transmis au lancement, pour assister aux erreurs internes.
Existe également le module NodeJS, créé pour l'application Vue.js. Code source que vous pouvez trouver dans le dossier js .
Les objets en temps réel ne doivent pas passer entre les fils.
Pour exécuter l'exemple de projet, clonez le repo et exécutez d'abord pod install à partir de l'exemple du répertoire.
Xcode 9+, Swift 4.1+.
Swiftpm
. package ( url : " https://github.com/k-o-d-e-n/realtime.git " , . branch ( " master " ) )Le temps réel est disponible via Cocoapods. Pour l'installer, ajoutez simplement la ligne suivante à votre podfile:
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
En temps réel est disponible sous la licence du MIT. Voir le fichier de licence pour plus d'informations.