Comments (2)
This is both a limitation, and one of the principles of the pattern itself. The view models create a local state for the view, and therefore create a bridge between view <-> global state in this way. This does mean an element of duplication / "pass the parcel" goes on.
The upside of this is that the view model itself can perform its own modifications on global state where necessary, our view layer remains decoupled from global state, and this gives us a level of flexibility for refactoring.
I tend to create bindings in my view models, rather than use didSet in this way. This can come in handy for throttling calls to services so they don't get called too often when a user's typing, for example:
class LoginViewModel: BaseViewModel<Services>, ObservableObject {
@Published var searchString: String = ""
private var cancellables = Set<AnyCancellable>()
override init(services: Services) {
super.init(services: services)
self.setBindings()
}
private func setBindings() {
self.$searchString
.throttle(for: .milliseconds(500), latest: true)
.sink { [weak self] searchString in
self?.services.dataManager.search(searchString)
}
.store(in: &self.cancellables)
}
}
from swiftui-router.
Thanks for the explanation, it makes sense and I like the separation from global state that this method brings.
The observation with throttling is a nice touch and does solve a lot of performance issues that developers tend to run into while working with SwiftUI 😄
In my case I wanted two-way observation which is a bit more annoying. There is also a problem in both of our examples that the global state will be assigned upon view model creation, because the initial value given from the observer creation will trigger it to assign it to the global state. So just visiting this view will trigger a global state to update (even if it's to the same value it already was). A dropFirst()
can solve this.
I tried cleaning this up a bit and came up with the following:
Letting all my BaseViewModel
s become ObservableObjects
by default.
Define var cancellables
and an empty setupBindings()
on the superclass.
open class BaseViewModel<S>: ObservableObject {
public var services: S
var cancellables = Set<AnyCancellable>()
public init(services: S) {
self.services = services
setupBindings()
}
func setupBindings() {
// Override in subclass
}
}
Add a Publisher extension specifically for the use case of binding view model state to global state, with optional throttling:
extension Publisher where Output: Equatable, Failure == Never {
func assignViewModelState<Root>(to keyPath: ReferenceWritableKeyPath<Root, Self.Output>, on object: Root, throttle: Bool = false) -> AnyCancellable {
self
.dropFirst()
.throttle(for: throttle ? .milliseconds(200) : 0, scheduler: RunLoop.main, latest: true)
.removeDuplicates()
.assign(to: keyPath, on: object)
}
}
Then the view model becomes:
class AccountScreenViewModel: BaseViewModel<Services> {
@Published var isAway: Bool = false
override func setupBindings() {
services.loginManager.state.$isAway.assign(to: &$isAway)
$isAway
.assignViewModelState(to: \.isAway, on: services.loginManager.state)
.store(in: &cancellables)
}
}
It imposes a bit more on the View Model, but this is such a recurring use case that I think it's warranted. Seems to work pretty well so far. What do you think?
You should add a section about handling views that require Binding
to the blog post when you update it next time 👍
from swiftui-router.
Related Issues (5)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from swiftui-router.