Реальное время - это ORM Framework, которая делает создание сложных структур баз данных просты.
Простая масштабируемая структура модели
Файлы
Коллекции
Ссылки
UI, форма
База данных Firebase Realtime полностью поддерживается и используется в производстве. Если вы используете API Clean Firebase, Realtime может помочь в создании приложения быстрее, при этом применить сложные структуры для хранения данных, для обновления пользовательского интерфейса с использованием реактивного поведения. Realtime обеспечивает легкий трафик данных, ленивую инициализацию данных, хорошее распределение данных.
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 Properties, вам нужно реализовать функцию класса lazyPropertyKeyPath(for:) . (Пожалуйста, скажите, если вы знаете, как это избегаете, без наследства NSOBject). Эта функция требует каждого подкласса, поэтому вам не нужно вызовать супер реализацию. Пример: 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 - Hereonly хранится свойство для файла в хранилище 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 to 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
}(Явные) Связанные Values - это словарь, где ключи являются ссылками, но значения являются объектами. В сохранении значения создает ссылку на стороне ключевой объект.
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
}<== - Оператор назначения. Можно использовать для назначения (или для получения) значения (из) любого Propport.==== ,! !=== - Операторы сравнения. Может использовать для сравнения любых свойств в реальном времени, где их значения соответствуют Equatable протоколу.?? - Оператор Infix, который выполняет операцию по уплате нуля, возвращая обернутое значение свойства в реальном времени или значение по умолчанию.<- - оператор префикса. Может использовать для преобразования экземпляра 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 )Для получения более подробной информации см. Пример проекта.
SingleSectionTableViewDelegate - предоставляет источник данных в отдельном разделе для UitableView с автоматическим обновлением. SectionEdtableViewDelegate - предоставляет раздел «Источник данных» для 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 .
Объекты в реальном времени не должны проходить между потоками.
Чтобы запустить пример проекта, клонируйте репо, и сначала запустите pod install из Directory Directory.
Xcode 9+, Swift 4.1+.
Swiftpm
. package ( url : " https://github.com/k-o-d-e-n/realtime.git " , . branch ( " master " ) )Реальное время доступно через кокопод. Чтобы установить его, просто добавьте следующую строку в свой 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
Реальное время доступно по лицензии MIT. Смотрите файл лицензии для получения дополнительной информации.