SwiftEvents is a lightweight library for creating and observing events.
It includes:
Observable<T>
- a type-safe class for data binding that can be particularly used in MVVM.Event<T>
- a type-safe class for any notifications, including one-to-many with multiple subsribers.SwiftEvents has a thread-safe version - EventTS<T>
and ObservableTS<T>
classes. This way, its properties and methods can be safely accessed by multiple threads at the same time.
Another important feature is the automatic unsubscription of subscribers/observers when they are deallocated.
Comprehensive unit test coverage.
To install SwiftEvents using the Swift Package Manager:
Xcode: File -> Add Packages
Enter Package URL: https://github.com/denissimon/SwiftEvents
To install SwiftEvents using CocoaPods, add this line to your Podfile
:
pod 'SwiftEvents', '~> 2.1'
To install SwiftEvents using Carthage, add this line to your Cartfile
:
github "denissimon/SwiftEvents"
Copy SwiftEvents.swift
into your project.
Example:
class ViewModel {
let items: Observable<[SomeItem]> = Observable([])
let infoLabel: Observable<String> = Observable("")
}
class View: UIViewController {
var viewModel = ViewModel()
@IBOutlet weak var infoLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
bind()
}
private func bind() {
viewModel.items.bind(self) { [weak self] _ in self?.updateItems() }
viewModel.infoLabel.bind(self) { [weak self] in self?.updateInfoLabel($0) }
}
private func updateItems() { ... }
private func updateInfoLabel(_ newText: String) {
infoLabel.text = newText
}
}
In this example, every time the ViewModel changes the value of the observable property items
or infoLabel
, the View is notified and updates its UI.
The infix operator <<< can be used to set a new value for an observable property:
items.value = newData
items <<< newData
Example implementation of the closure-based delegation pattern:
class MyModel {
let didDownload = Event<UIImage?>()
func downloadImage(for url: URL) {
service.download(url: url) { [weak self] image in
self?.didDownload.notify(image)
}
}
}
class MyViewController: UIViewController {
let model = MyModel()
var image: UIImage?
override func viewDidLoad() {
super.viewDidLoad()
model.didDownload.subscribe(self) { [weak self] image in self?.updateImage(image) }
}
private func updateImage(_ image: UIImage?) {
self.image = image
}
}
You can also create several events (didDownload, onNetworkError etc), and trigger only what is needed.
Event and Observable conform to Unsubscribable
and Unbindable
protocols respectively, which allows to pass a reference to an object that should only call unsubscribe
/ unbind
.
More usage examples can be found in iOS-MVVM-Clean-Architecture.
Also tests contains a NotificationCenter-like implementation, and here is a gist with a cell-to-cellViewModel binding example.
Deallocated subscribers/observers are automatically removed from Event/Observable. But they also can be removed manually:
someEvent.subscribe(self) { [weak self] in self?.setValue($0) }
someEvent.unsubscribe(self)
someObservable.bind(cell) { [weak cell] in cell?.update($0) }
someObservable.unbind(cell)
someEvent.unsubscribeAll()
someObservable.unbindAll()
someEvent.subscribersCount
someObservable.observersCount
someEvent.triggersCount
someObservable.triggersCount
By default, the provided handler is executed on the thread that triggers the Event/Observable. To change this default behaviour:
// This executes the handler on the main thread
someEvent.subscribe(self, queue: .main) { [weak self] in self?.updateTable($0) }
someObservable.bind(self, queue: .main) { [weak self] in self?.updateTable($0) }
To ensure that the handler will be executed only once:
someEvent.subscribe(self) { [weak self] data in
guard let self = self else { return }
self.useData(data)
self.someEvent.unsubscribe(self)
}
To ensure that the handler will be executed no more than n
times:
someEvent.subscribe(self) { [weak self] data in
guard let self = self else { return }
self.useData(data)
if self.someEvent.triggersCount >= n { self.someEvent.unsubscribe(self) }
}
Licensed under the MIT license
link |
Stars: 5 |
Last commit: 4 days ago |
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics