UsefulNetworkLayer uses new Swift Package Manager which is easiest way introduced for iOS projects since from the beginning.
From Xcode simply select File > Swift Packages > Add Package Dependency... and paste https://github.com/exozet/iOSUsefulNetworkLayer to search field. You can specify rules according to your preferences and you are ready to use.
NetworkLayer needs an object which is inherited from ResponseBodyParsable class in order to create responses. There is two required initializer from that object, whether from the Data or JSON object. One of them should return nil to give access to other initializer.
In below, Response object will be created from the JSON response:
/// Initializes object from JSON response.
class ExampleResponseObject: ResponseBodyParsable {
var userId: Int
var id: Int
var title: String
var completed: Bool
required init?(_ data: Data) {
return nil
}
required init?(_ response: Any?) {
guard let dict = response as? [String:Any] else { return nil }
guard let userId = dict["userId"] as? Int,
let id = dict["id"] as? Int,
let title = dict["title"] as? String,
let completed = dict["completed"] as? Bool else { return nil }
self.userId = userId
self.id = id
self.title = title
self.completed = completed
super.init(response)
}
}Or using data, for instance image, can be created by the data response:
/// Initializes object from Data.
class ExampleImageObject: ResponseBodyParsable {
var image: UIImage
required init?(_ data: Data) {
guard let image = UIImage(data: data) else {
return nil
}
self.image = image
super.init(data)
}
required init?(_ response: Any?) {
return nil
}
}Using highly customizable APIConfiguration object, API requests can be defined easily and requests from Network Layer.
In below example, uses ExampleResponseObject as a response model to create API configuration with basic parameters.
let api = APIConfiguration(hostURL: "https://jsonplaceholder.typicode.com",
endPoint: "todos/1",
responseBodyObject: ExampleResponseObject.self)Or, advanced parameters can be applied.
let api = APIConfiguration(hostURL: "https://jsonplaceholder.typicode.com",
endPoint: "todos/1",
requestType: .get,
headers: nil, body: nil,
responseBodyObject: ExampleResponseObject.self,
priority: .low,
cachingTime: .init(seconds: 60),
isMainOperation: false, autoCache: false)When operation is completed, completion block will return with two cases, whether error or successful response.
guard let apiReq = api else {
print("Something wrong with the configuration")
return
}
apiReq.request { (result) in
switch result {
case .error(let errResponse):
print("Error: \(errResponse.error.localizedDescription)")
case .success(let successfulResponse):
print("Response Body: \(successfulResponse.responseBody)")
}
}In default, responses will be cached by the given cachingTime property. However, ResponseBodyParsable gives flexibility to define time value dynamically from the object itself. By overriding cachingEndsAt: method from the object, new time value for cache expiry can be defined.
In below, same example object overrides the method and uses, for instance one of the variables in the response to define caching expiry.
/// Initializes object from JSON response.
class ExampleResponseObject: ResponseBodyParsable {
var userId: Int
var id: Int
var title: String
var completed: Bool
var expiry: Date?
required init?(_ data: Data) {
return nil
}
required init?(_ response: Any?) {
guard let dict = response as? [String:Any] else { return nil }
guard let userId = dict["userId"] as? Int,
let id = dict["id"] as? Int,
let title = dict["title"] as? String,
let completed = dict["completed"] as? Bool else { return nil }
self.userId = userId
self.id = id
self.title = title
self.completed = completed
// gets expiry value from the response
self.expiry = dict["expiry"] as? Date
super.init(response)
}
override func cachingEndsAt() -> Date? {
return self.expiry
}
}Then, in the API configuration, autoCache parameter should be set to true.
iOSUsefulNetworkLayer holds two queues, one is called as main and the other one as background. In default, all request operations will be handled in the background queue unless isMainOperation property is set to true. It effects resource levels in the system level to use more resources, so requests which should needs to get answered and completed as soon as possible can moved into the main queue to use more resources from the system.
In addition, for the each request operation in the same queue will be handled by looking their priority specification. In default, all requests are marked as normal level, but by using that property more important requests can be moved into top by giving higher priority.