Combine and URLSession in UIKit
Difficulty: Beginner | Easy | Normal | Challenging
This article has been developed using Xcode 11.4.1, and Swift 5.2.2
This article is about using
Combine in conjunction with
UIKit in order to get the basics of the former down without the expectation of knowledge about SwiftUI. This implementation calls a network manager much like a login for any particular App.
I’m not going to use storyboards, but am going to use UIKit and MVVM to keep things rather simple. I’m going to apply some Dependency Injection skills in order to test
URLSession, and this uses a keychain manager to save the token (which is also tested).
- You will be expected to be aware how to make a Single View Application in Swift.
- I recommend that you download the repo and read the code along with this article, although I have written the article to be a stand-alone document
Combine: A framework that provides a declarative Swift API for processing values over time
Combine has many possible uses, and we are not constrained when linking
The example code shows instances of:
- Setting up pipelines to lock a
UIButtonuntil the values entered into a
- Create a pipeline to perform an asynchronous network call, choosing how and what to update within a view
- Create a pipeline to adjust the state of a
UIButtondynamically according to the text in a
UITextFieldupdating the user interface accordingly
You know what this reminded me of?
The App has a simple login and a material-design alike interface. When the username and password are entered, the view controller asks the viewmodel to make an API call.
For fun, I made the views have a
xib file although the project has been created with a
storyboard, using this technique.
Each of the following sections focus on the
LoginView sections of the App enclosed in the repo, but similar ideas are sprinkled through the App as a whole.
The View Controller
LoginViewController is not substantially different from any
UIViewController that you might write in
Initially I left the cancellable objects
AnyCancellabl` as single vars in the project class. The reason that *any* of these exist is that a transaction may be cancelled when the token is
whereas a better approach is to store these
private var subscriptions = Set<AnyCancellable>()
perhaps in an
array as shown above, and then the binding can be stored in the array:
I’ve decided to create view model instances that conform to a protocol (indeed, the
UserDataManager() does the same thing)
on the side of the view model we can bind to a
AnyPublisher<Bool, Never> in a view model, and the view can be attached accordingly (here updating the
likewise we can bind out
UITextField to a
@Published var username: String = "" which is situated in the view model.
which of course links ot the selector as defined:
The View Model
The view model has two
@Published var which creates a publisher of this type, which can then be accessed through use of the
validLengthUsername is defined as the following, where
debounce is used ensuring we only receive elements when the user pauses or stops typing.
removeDuplicates ensures that only distinct elements are used.
similarly we check the password
and both of these use
eraseToAnyPublisher to make the
publisher visible to the downstream
To combine the two,
.zip is used to combine the two operators together, and that’s an awesome.
of course this is subscribed to in the view controller (as shown above).
API calls are made from this view model (actually upon the pressing of a button in the view controller)
This makes use of
sink in order to store the token in the keychain, and then send a message back to the view controller using
shouldNavSubject is an
AnyPublisher<Bool, Never> that leverages
PassthroughSubject which is an operator sitting in between a
Networking is taken care of by a
HTTPManager as defined below, but the approach that is taken is much like my basic network manager in that a
protocol is used — and the
URLSession can be swapped out during testing so when we make API calls they aren’t actually hitting the
API (in testing, of course)
We can come onto the testing later in this article.
Since we are using that
URLSession that is replaceable during testing. This is quite tricky when using
dataTaskPublisher — here is the approach to obtain the correct
Failure types by creating a
protocol that we get
URLSession to conform to, creating a
typealias that can be returned by the actual class or the mocked version.
As has been mentioned above, we can mock
which can then be used by a mocked
This is then setup in the test classes themselves since we can setup
adding a test
Which means, crucially, that we don’t use a real
API call to get data during testing and instead we get the data from a
json file in the test target — that’s a good job all round.
This article is a rather useful implementation of
UIKit, we can see this in this article.
It is rather complex in the description, but rather easy in the implementation. Take a look at the attached Repo. It is a rather wonderful thing.
People do like Apple’s documentation on this topic.
If you’ve any questions, comments or suggestions please hit me up on Twitter