Binding for iOS

Inspired by LiveData from Android Architecture Components.
Observable concept
There are three classes that can be observed: LiveData
, FutureEvent
and SingleEvent
.
LiveData
and FutureEvent
implements Observable
protocol. SingleEvent
is special case of FutureEvent
and implements SingleEventObservable
protocol.
Unlike a regular observation pattern, Observable
(and SingleEventObservable
) is lifecycle-aware, meaning it respects the lifecycle of its owner. This awareness ensures Observable
only updates app component observers that are in an active lifecycle state.
You can register an observer paired with an object that is LifecycleOwner
(typealias for AnyObject). This relationship allows the observer to be removed when the state of the corresponding LifecycleOwner
changes to deallocated. This is especially useful for view controllers because they can safely observe objects from view model and not worry about leaks.
When to use LiveData
, FutureEvent
and SingleEvent
LiveData
– holds state/data. State changes can be observed.
FutureEvent
– doesn’t hold state, just notify observers when event is triggered. Event can has associated value.
SingleEvent
– is special case of FutureEvent
. Delivers only the first triggered event.
Advantages
No memory leaks
Observers are bound to lifecycle objects and clean up after themselves when their associated lifecycle is destroyed.
Safe [unowned self]
Because Observer is bound to lifecycle, it will never happens that observer is updated if LifecycleOwner
is deallocated.
No more manual lifecycle handling
UI components just observe relevant data and don’t stop observation. Observable
automatically manages this since it’s aware of the relevant lifecycle status changes while observing.
Installation
CocoaPods
Add pod 'ETBinding'
to your Podfile.
Carthage
Add github "EtneteraMobile/ETBinding"
to your Cartfile.
Swift Package Manager
In Xcode (>11.0) go to File -> Swift Packages -> Add Package Dependency. There insert https://github.com/EtneteraMobile/ETBinding
in URL input and finish importing ETBinding
to your project.
Usage
Follow these steps to work with LiveData
objects:
- Create an instance of
LiveData
to hold a certain type of data. This is usually done within your ViewModel class.
- Create an
Observer
object that defines the update closure, which controls what happens when the LiveData
object’s held data changes. You usually create an Observer
object in a view controller.
- Attach the
Observer
object to the LiveData
object using the observe
method. The observe
method takes a LifecycleOwner
object. This subscribes the Observer
object to the LiveData
object so that it is notified of changes.
Note: You can register an observer without an associated LifecycleOwner
object using the observeForever
method. In this case, the observer is considered to be always active and is therefore always notified about modifications. You can remove these observers calling the removeObserver
method.
When you update the value stored in the LiveData
object, it triggers all registered observers as long as the attached LifecycleOwner
is in the active state.
Observe with lifecycle owner
Observation starts only with owner and update closure, then new instance of Observer
is returned. This observer can be ignored in case when future remove isn’t needed.
let liveData: LiveData<String> = LiveData()
let observer = liveData.observe(owner: self) { data in
// do something with data
}
// observer can be used for later unregistration
Update closure can be encapsulated inside Observer
and after then registered. This pattern could be used when observation will be started in future.
let observer: Observer<String?> = Observer(update: { data in
// do something with data
})
// … and later
let liveData: LiveData<String> = LiveData()
liveData.observe(owner: self, observer: observer)
// observer can be used for later unregistration
Observe forever
Lifecycle owner isn’t mandatory all the time. When owner isn’t given, unregistration is under your control.
let liveData: LiveData<String> = LiveData()
let observer = liveData.observeForever { data in
// do something with data
}
// observer can be used for later unregistration
let observer: Observer<String?> = Observer(update: { data in
// do something with data
})
// … and later
let liveData: LiveData<String> = LiveData()
liveData.observeForever(observer: observer)
// observer can be used for later unregistration
Remove observer
Unregisters given observer from liveData changes observation.
// … observer is obtained from early called function `observe`
liveData.remove(observer: observer)
Dispatch value to observers
After observation is started value isn’t automatically dispatched to observer. If you want to gain current value, you can read it directly from data
variable or you can call dispatch
and update will be delivered to newly registered observers.
// Dispatches value to observers that were registered from last dispatch
liveData.dispatch()
// Dispatches value to given observer if is newly registered from last dispatch
liveData.dispatch(initiator: observer)
Every observer is called only once per new value although dispatch
is called multiple times. Value setter is versioned and observer holds last delivered value version and blocks dispatching of version that was already delivered.
Contributing
Contributions to ETBinding are welcomed and encouraged!
License
ETBinding is available under the MIT license. See LICENSE for more information.
Attributions
I’ve used SwiftPlate to generate xcodeproj compatible with CocoaPods and Carthage.
Binding for iOS
Inspired by LiveData from Android Architecture Components.
Observable concept
There are three classes that can be observed:
LiveData
,FutureEvent
andSingleEvent
.LiveData
andFutureEvent
implementsObservable
protocol.SingleEvent
is special case ofFutureEvent
and implementsSingleEventObservable
protocol.Unlike a regular observation pattern,
Observable
(andSingleEventObservable
) is lifecycle-aware, meaning it respects the lifecycle of its owner. This awareness ensuresObservable
only updates app component observers that are in an active lifecycle state.You can register an observer paired with an object that is
LifecycleOwner
(typealias for AnyObject). This relationship allows the observer to be removed when the state of the correspondingLifecycleOwner
changes to deallocated. This is especially useful for view controllers because they can safely observe objects from view model and not worry about leaks.When to use
LiveData
,FutureEvent
andSingleEvent
LiveData
– holds state/data. State changes can be observed.FutureEvent
– doesn’t hold state, just notify observers when event is triggered. Event can has associated value.SingleEvent
– is special case ofFutureEvent
. Delivers only the first triggered event.Advantages
No memory leaks
Observers are bound to lifecycle objects and clean up after themselves when their associated lifecycle is destroyed.
Safe [unowned self]
Because Observer is bound to lifecycle, it will never happens that observer is updated if
LifecycleOwner
is deallocated.No more manual lifecycle handling
UI components just observe relevant data and don’t stop observation.
Observable
automatically manages this since it’s aware of the relevant lifecycle status changes while observing.Installation
CocoaPods
Add
pod 'ETBinding'
to your Podfile.Carthage
Add
github "EtneteraMobile/ETBinding"
to your Cartfile.Swift Package Manager
In Xcode (>11.0) go to File -> Swift Packages -> Add Package Dependency. There insert
https://github.com/EtneteraMobile/ETBinding
in URL input and finish importingETBinding
to your project.Usage
Follow these steps to work with
LiveData
objects:LiveData
to hold a certain type of data. This is usually done within your ViewModel class.Observer
object that defines the update closure, which controls what happens when theLiveData
object’s held data changes. You usually create anObserver
object in a view controller.Observer
object to theLiveData
object using theobserve
method. Theobserve
method takes aLifecycleOwner
object. This subscribes theObserver
object to theLiveData
object so that it is notified of changes.Note: You can register an observer without an associated
LifecycleOwner
object using theobserveForever
method. In this case, the observer is considered to be always active and is therefore always notified about modifications. You can remove these observers calling theremoveObserver
method.When you update the value stored in the
LiveData
object, it triggers all registered observers as long as the attachedLifecycleOwner
is in the active state.Observe with lifecycle owner
Observation starts only with owner and update closure, then new instance of
Observer
is returned. This observer can be ignored in case when future remove isn’t needed.Update closure can be encapsulated inside
Observer
and after then registered. This pattern could be used when observation will be started in future.Observe forever
Lifecycle owner isn’t mandatory all the time. When owner isn’t given, unregistration is under your control.
Remove observer
Unregisters given observer from liveData changes observation.
Dispatch value to observers
After observation is started value isn’t automatically dispatched to observer. If you want to gain current value, you can read it directly from
data
variable or you can calldispatch
and update will be delivered to newly registered observers.Every observer is called only once per new value although
dispatch
is called multiple times. Value setter is versioned and observer holds last delivered value version and blocks dispatching of version that was already delivered.Contributing
Contributions to ETBinding are welcomed and encouraged!
License
ETBinding is available under the MIT license. See LICENSE for more information.
Attributions
I’ve used SwiftPlate to generate xcodeproj compatible with CocoaPods and Carthage.