الوقت الحقيقي هو إطار ORM الذي يجعل إنشاء هياكل قاعدة البيانات المعقدة أمرًا بسيطًا.
بنية نموذجية بسيطة قابلة للتطوير
الملفات
مجموعات
مراجع
واجهة المستخدم ، شكل
يتم دعم قاعدة بيانات Firebase Realtime بالكامل وتستخدمها في الإنتاج. إذا كنت تستخدم Clean Firebase API ، فيمكن أن تساعد الوقت الحقيقي في إنشاء تطبيق بشكل أسرع ، طيه لتطبيق هياكل معقدة لتخزين البيانات ، لتحديث واجهة المستخدم باستخدام السلوكيات التفاعلية. يوفر الوقت الحقيقي حركة بيانات خفيفة الوزن ، والتهيئة البطيئة للبيانات ، وتوزيع البيانات الجيدة.
يتم دعم FoundationDB ، ولكن مع بعض القيود ، لأن FDB ليس لديه آليات مراقبة أصلية.
في AppDelegate في func application(_:didFinishLaunchingWithOptions:) يجب عليك الاتصال بالرمز أدناه ، لتكوين بيئة العمل. الآن بالنسبة لسياسة ذاكرة التخزين المؤقت هي case .noCache, .persistance فقط. لم يتم تنفيذ ذاكرة التخزين المؤقت في الذاكرة بعد.
func application ( _ application : UIApplication , didFinishLaunchingWithOptions launchOptions : [ UIApplicationLaunchOptionsKey : Any ] ? ) -> Bool {
/// ...
/// initialize Realtime
RealtimeApp . initialize ( ... )
///...
return true
} لإنشاء أي بنية بيانات نموذج يمكنك صنعها عن طريق تصنيف Object فرعي. يمكنك تحديد خصائص الطفل باستخدام الفصول:
Object الفئات الفرعيةReadonlyProperty ، Property ، Reference ، Relation ، ReadonlyFile ، File ؛References ، Values ، AssociatedValues ، وهلم جرا ؛ إذا كنت تستخدم خصائص Lazy ، فأنت بحاجة إلى تنفيذ وظيفة الفصل lazyPropertyKeyPath(for:) . (من فضلك قل لي إذا كنت تعرف كيف تجنب ذلك ، دون وراثة nsobject). استدعت هذه الوظيفة لكل فئة فرعية ، وبالتالي لا تحتاج إلى تنفيذ Super Call. مثال: 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 - خاصية مخزنة READONLY لأي قيمة.
خاصية - خاصية مخزنة لأي قيمة.
المرجع - المتاجر المرجع على أي قيمة قاعدة بيانات. لا يعني النزاهة المرجعية. استخدمه إذا لم تتم إزالة السجل وإلا السبب الآخر الذي لا يحتاج إلى سلامة مرجعية.
العلاقة - مرجع المتاجر على أي قيمة قاعدة بيانات.
ReadOnlyFile - خاصية مخزنة للقراءة للملف في تخزين Firebase.
ملف - خاصية مخزنة للملف في تخزين FireBase.
تتبنى جميع الخصائص ميزة @propertyWrapper ، ولكن على الرغم من أن Swift لا بد أدلة إلى self في خصائص كسول مخصصة ، وبهذه الطريقة لتحديد الخصائص غير المجدية عمومًا.
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 )
} يمكن أن تتطلب بعض العمليات القابلة للتغيير للمجموعات حالة isSynced . لتحقيق هذه الحالة ، استخدم وظيفة func runObserving() أو تعيين خاصية keepSynced: Bool إلى true .
(موزعة) المراجع هي صفيف تخزن الكائنات كمراجع. يجب أن تحدد عناصر المصدر في نفس المرجع. عند إدراج كائن في هذه الصفيف ، ينشئ رابط على كائن جانبي.
(صريحة) القيم هي صفيف تخزن الكائنات حسب القيمة في حد ذاته الموقع. يتم استخدام البادئة "الصريحة" في المجموعة التي تخزن عناصر دون عرض جمع.
References ، Values المتحولة:
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
}(صريح) القيم المرتبطة به هو القاموس حيث تكون المفاتيح مراجع ، ولكن القيم هي كائنات. على قيمة حفظ ، ينشئ الرابط على كائن المفتاح الجانبي.
AssociatedValues المرتبطة بها:
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 هي مجموعة غير قابلة للتغيير تحصل على عناصر من وظيفة الخريطة. هذه هي نتيجة X.Lazymap (_ Transform :) الطريقة ، حيث X هي أي شيء حقيقي.
let userNames = Values < User > ( in : usersNode ) . lazyMap { user in
return user . name
}<== - عامل المهمة. يمكن استخدامه لتعيين (أو لاسترداد) القيمة إلى (من) أي خاصية في الوقت الحقيقي.==== ، !=== - عوامل المقارنة. يمكن استخدامه لمقارنة أي خصائص في الوقت الحقيقي حيث تتوافق قيمها مع البروتوكول Equatable .?? - مشغل Infix ، الذي يؤدي عملية Nil-Coalescing ، وإرجاع القيمة ملفوفة لخاصية في الوقت الفعلي أو قيمة افتراضية.<- - مشغل البادئة. يمكن استخدامه لتحويل مثيل Closure, Assign أنواع لإغلاق صريح أو للخلف.المعاملة - كائن يحتوي على جميع المعلومات حول معاملات الكتابة. تقريبا جميع تغييرات البيانات تنفيذ باستخدام هذا الكائن. تأخذ العمليات الأكثر قابلية مجرد معاملة كمعلمة ، ولكن لإنشاء عمليات معقدة مخصصة ، يمكنك استخدام هذه الطرق:
/// 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 )لمزيد من التفاصيل ، انظر مثال المشروع.
SIDSENSECTIONTABLEVIEWDELEGATE - يوفر مصدر بيانات قسم واحد لـ UITALLVIEW مع تحديث تلقائي. ConceedTableViewDelegate - يوفر مصدر بيانات مقطوع لـ UitableView مع تحديث تلقائي. CollectionViewDelegate - يوفر مصدر بيانات لـ UICollectionView مع تحديث تلقائي.
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 ) متاح كوحدة منفصلة مع الدعم 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
}
}لتلقي التغييرات على المستوى المحلي ، استخدم الكائنات التي تتوافق مع هذا البروتوكول. لديها واجهة Rxswift مماثلة.
public protocol Listenable {
associatedtype OutData
/// Disposable listening of value
func listening ( _ assign : Assign < OutData > ) -> Disposable
}إضافة وسيطة تصحيح "realtime_crash_on_error" تم تمريرها على الإطلاق ، لالتقاط الأخطاء الداخلية.
يوجد أيضًا وحدة NodeJS ، تم إنشاؤها لتطبيق Vue.js. رمز المصدر الذي يمكنك العثور عليه في مجلد js .
لا ينبغي أن تمر كائنات الوقت الحقيقي بين المواضيع.
لتشغيل Project Example ، استنساخ REPO ، وتثبيت pod install من الدليل المثال أولاً.
Xcode 9+ ، Swift 4.1+.
Swiftpm
. package ( url : " https://github.com/k-o-d-e-n/realtime.git " , . branch ( " master " ) )يتوفر الوقت الحقيقي من خلال Cocoapods. لتثبيته ، ما عليك سوى إضافة السطر التالي إلى 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
يتوفر الوقت الحقيقي بموجب ترخيص معهد ماساتشوستس للتكنولوجيا. انظر ملف الترخيص لمزيد من المعلومات.