Implement Two-Way UIKit Binding in Vanilla Swift
Avoid third parties if you can!

Difficulty: Beginner | Easy | Normal | Challenging
This article has been developed using Xcode 12.1, and Swift 5.3, and certain features (\String.self keypath) require Swift 5+
If you would just like to use the library, head over to https://github.com/stevencurtis/TwoWayBindingUIKit and use Swift Package Manager to install it!
Prerequisites:
- You will be expected to be aware how to make a Single View Application in Swift
- I have taken a programmatic approach to the interface, although this is unlikely to trip you up (the guide is here)
- Keypaths are a major factor in the ultimate solution in this article
- If you’d like to take a look at the theory of the Mediator Pattern that might give you a hand
- There is some mention of optionals
- We have some Generics in Swift
- You would also need some knowledge about extensions and protocols
MVVM is a fantastic Architecture pattern for iOS. However, if you do not implement the two-way binding you are likely to end up with the subtly different MVP architecture.
The answer? Use two-way bindings. One way to do this is to add RxSwift or other dependencies into your code. Don’t want to add those third-party libraries? Read on to find out how to avoid bloating your code for these bindings.
Terminology
Binding: A technique that binds data sources from the provider and consumer together and synchronizes them MVVM: An architecture pattern consisiting of Model, View and View-Model Observable: An emitter of notifications of a change Observer: An object that wishes to be notified when the state of another object changes. Subscribe: An observer lets a subject know that it wants to be informed of changes through a process called subscribing Subscriber: A term meaning Observer Type: A representation of the tyoe of data that can be processed, for example Integer or String
Loose coupling
The open-closed principle says that implementation should hide behind an interface — that is; loose coupling.

Two-way binding means that we can connect the View to the View Model. The idea is that the View and the View Model are held in sync.

Since the View Model mediates in between the view and the model it no only updates the view, but updates it. That is, two-way (bi-directional) binding, in the style of The Mediator Pattern.
Observables are at the heart of reactive programming (although they do not cover the entire range of reactive programming as the principes at work go beyond just this. Effectively this functionality is inbuilt in RxSwift however our own implementation can avoid needing to import that rather large third-party library!
The project
I’m going to create a rather dull project that has three UITextField
components on it, each of which will implement two-way binding in slightly different ways. This finished project looks just like the following image:

Now of course since these are UITextField
components you can download the repo, take a look and change what they say!
Now this particular project does not use storyboards as I have opted for a programmatic approach.
The first UITextField Observing a String, AKA one-way binding fixed to be two-way
The UITextField
called firstTF
is connected to a String
in the ViewModel
, but in this case we aren't going to use a simple String
- this is going to be an Observable - that is, a type that can be observed, and I've constructed this as a class.
We can then observe any changes that are made from the ViewModel
Now we need to keep the original value in the ViewModel
synchronised. To do so we can set the delegate of the text field, and update the value in the view model.
So that Observable
class looks like the following:
essentially we take an optional value
(so this works with optional type). Essentially we assign the value during initialization, and when we observe the value the observer is added to an array of observers, and initially (and when the value is changed) the completion handler is called.
In the code in the repo you’ll see that I’ve used a delay with DispatchQueue.main.asyncAfter
- something I would not do in production code. No, a better way of testing code is to use testing:
I did use DispatchGroups in the full tests in the Repo so please do try to take a look there if you want the full details!
One difficulty with this approach is that when we type a change in the firstTF
text field the UITextField
will be updated twice (so there would be a performance penalty for using this approach, which (to be honest) is not two-way binding at all as we have to perform extra work in the delegate function of UITextField
.
We therefore need to find a better approach!
The second UITextField
The secondTF
uses a bind function (which is actually a two-way binding) as:
which once again connects to an Observable
:
Now Bindable
itself is a protocol:
which any specific UIControl
conforms to - in this case we are using UITextField
as an example. This uses the Observable
class as defined in the previous section of this article, and leverages a UITextFieldDelegate
within an extension.
Here is the protocol, and the extension:
Now this can be improved by using the improved version of Stored Properties in this article, but this implementation does indeed work:
so…
So we have avoided having the delegate of the UITextField
in the UIViewController
, but that comes at a real cost - what if we want to use any of these delegate functions in our own code? Well, certainly we could use NSNotificationCenter
but even if we went down that road, there would be another problem.
We’d have to write this extension for each and every control that would be used. This would be, quite clearly, awful. There has to be a better way.
In steps the third example.
The third example
We can use keypaths to make a MakeBindable
type that we will use in place of the Observable
type we used before:
which is then bound using the following:
So MakeBindable
is a class, where we can optionally add an initial value, that is:
with functions that use generics to bind AnyObject
to specific keypaths.
The initializer optionally creates the inititial value (which, as it can change is called previousValue
which would represent the previous value in a stream of values.
the bind function as the entry point to add the observer, using the keypath as chosen using the following:
which itself calls the following private function:
which of course, when updated will call each of these observers:
Further testing
This all sounds great until we look into the detail. More testing is required!
We have implemented better one-way binding, but haven’t yet implemented two-way binding! Curses!
Improving the MakeBindable
class
We will need a function to show us the current value
now when the binding type is a UIControl
I would like to update the value, using a function something like:
Where we run the new value to each of the observers, and update our previousValue
.
In itself this function is created when we bind the values, here is the updated bind function:
which of course relies upon the Keypath property:
Which we can then use, for example we can bind a UILabel
to a property called value
:
This all seems nice and fine. However, we might want to bind different values. To do so we would need to have some sort of mapping functions:
which can then be implemented with the following binding function that functions in a similar way as has been explained above:
Which can then be used (for example to bind a boolean to a label:
Finishing up
The code in the view controller can be simplified with the implementation of two-way binding. Therefore the testing code I have added in the repo may be of interest, especially since I’ve added the subclassed UITextField
here, with some small tests:
Now remember: This MakeBindable
class can be used for any controls. Wonderful!
Conclusion
Two-way binding without using RxSwift
or similar? That's interesting as we can see how the functions should work, and we can even have a great new use for KeyPaths
.
Keeping our Apps small and efficient? That is certainly something that we should be doing as we create better and better Apps. Take a look at the repo, and in particular the second UIViewController
that has examples of a series of controls. I hope this helps you out!
This article even contains testing so you can be sure that this deal with your ⌘U
to your hearts content. I hope you have enjoyed this article.
Isn’t that nice? It sure is!
If you’ve any questions, comments or suggestions please hit me up on Twitter