MVVM is a fantastic Architecture pattern for iOS, and is highly recommended to be used in your production code. However, if you do not implement the two-way binding your architecture better represents Model-View-Presenter (MVP).
Many developers will rely on RxSwift and RxCocoa to implement bindings, which is a rather heavyweight solution to simply implement Two-way binding.
This library offers an alternative: provide Two-way bind in a small, tested library.
This library is intended to be installed as a Swift Package guide, where you would add https://github.com/stevencurtis/SwiftCoding/TwoWayBindingUIKit
Bind to identical types
Values can be created as MakeBindable
var value: MakeBindable<String> = MakeBindable("Test Value")
lazy var label: UILabel = {
let lab = UILabel()
return lab
}()
which can then be bound to a UIControl
using a keypath: Providing the input and output are the same type (in this case, String
is the type for value
and the text of label
is also a String
)
value.bind(\String.self, to: lab, \.text)
Other uses include binding a UIButton
and it's isEnabled
property, for example:
var buttonEnabled: MakeBindable<Bool> = MakeBindable(true)
buttonEnabled.bind(\Bool.self, to: button, \.isEnabled)
Map bound types
If you would like to bind a value to a type that is different to that of the value, you need to provide a mapping function of the type (T) -> R?
.
A series of these are provided in this library:
Mappers.transformBoolToStringFunction Mappers.transformFloatToStringFunction Mappers.transformIntToStringFunction
Which are then passed to the bind function. A good example of hte use of this is where we can bind a Boolean value to the text of a UILabel
:
var switchValue: MakeBindable<Bool> = MakeBindable(true)
viewModel.switchValue.bind(
\Bool.self,
to: switchLabel,
\.text,
mapper: Mappers.transformBoolToStringFunction )
If you wish to use a mapper that is not provided, you may also use a mapper inline, and here is an example of how that may be implemented:
let transformBoolToStringFunction: (Bool) -> String = String.init(_:)
viewModel.switchValue.bind(\Bool.self, to: switchLabel, \.text, mapper: transformBoolToStringFunction)
There is a full post regarding this library at https://github.com/stevencurtis/SwiftCoding/TwoWayBinding