Bid Farewell to network layers with thread issues in your Swift code
Almost every app today connects to the internet. To make the connection appear smooth for the user, we, as developers write and manage a network layer and make sure there are no threading issues.
Earlier, we discussed about removing the network layer and working around threads separately. Now, if we put those two concepts together, we can end up writing almost no code to connect our app to the internet and never worry about threading issues. Again, we can use this in any app we write in Swift.
Here, let us solve the two most common use cases, for which we make network requests.
Whenever we make a network request, we either expect some JSON data, which we can convert to Swift objects using Codable or we expect a success status code, which is mostly 200 but can vary at times.
From our previous post, this is the getAlbums
use case, which returns either an array of Albums or an error.
class GetAlbums: MIUsecase, MINetworkable {
typealias MIUsecaseRequest = TypicodeRequest
typealias MIUsecaseResponse = Result<Albums, MINetworkError>
func execute(_ request: TypicodeRequest,
and callback: @escaping (Result<Albums, MINetworkError>) -> Void) {
send(request, returns: [Albums](), onCompletion: callback)
}
}
This class can be made generic, with the condition that success value of result type is any object conforming to Codable.
public class GetObject<T: Codable>: MIUsecase, MINetworkable {
public typealias MIUsecaseRequest = MIRequest
public typealias MIUsecaseResponse = Result<T, MINetworkError>
public func execute(_ request: MIRequest,
and callback: @escaping (Result<T, MINetworkError>) -> Void) {
send(request, returns: [T](), onCompletion: callback)
}
}
Now, in the AlbumsViewController
, you can replace the following line.
let getAlbums = GetAlbums()
With an object of the generic class returning Albums.
let getAlbums = GetObject<Albums>()
Yeah! That’s it. You can use this generic class to fetch whatever object you want from the internet. This is where combining protocols with generics has got us. Cool! 😎
In case you don’t want to directly decode to any Custom Swift type, like you are expecting an Image from your API, then you can pass Data
for the generic return type.
let getImage = GetObject<Data>()
Swift’s Data
type conforms to Codable
. So you can get any data you want using our generic usecase.
Now, let us move on to the other most common expectation from the network request, a status code.
public typealias MIResponseStatusCode = Intpublic class GetStatusCode: MIUsecase, MINetworkable {
public typealias MIUsecaseRequest = MIRequest
public typealias MIUsecaseResponse = Bool
private let code: MIResponseStatusCode
public init(_ code: MIResponseStatusCode) {
self.code = code
}
public func execute(_ request: MIRequest,
and callback: @escaping (Bool) -> Void) {
update(request, expecting: code, onCompletion: callback)
}
}
We can make a network request, expecting any status code, just by creating an object of this class. For example, to create an album on your server,
let createAlbum = GetStatusCode(200)
Now you can just perform the request, which conforms to MIRequest
, on this object.
createAlbum.perform(Request.create(album)) { isSuccess in // handle success or failure based on the Boolean here}
That’s it. You can now work with almost all of the APIs you need, without even writing any code to make network request. All you need is to make a Request Type, preferably an enum
, conforming to MIRequest
.
I’ve updated the pod MINetworkKit
with the MIUsecase
protocol and the two classes conforming to it. You can find the source code here.
You can install the pod by adding the following line to your Podfile.
pod ‘MINetworkKit’
When you write so little code, you have so little code to test and debug.
Code less, Do more, Have fun!