|
9 | 9 | 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. |
10 | 10 |
|
11 | 11 |
|
| 12 | +## Usage |
| 13 | + |
| 14 | +### Creating a response object |
| 15 | + |
| 16 | +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. |
| 17 | + |
| 18 | +In below, Response object will be created from the JSON response: |
| 19 | + |
| 20 | +```swift |
| 21 | +/// Initializes object from JSON response. |
| 22 | +class ExampleResponseObject: ResponseBodyParsable { |
| 23 | + |
| 24 | + var userId: Int |
| 25 | + var id: Int |
| 26 | + var title: String |
| 27 | + var completed: Bool |
| 28 | + |
| 29 | + required init?(_ data: Data) { |
| 30 | + return nil |
| 31 | + } |
| 32 | + |
| 33 | + required init?(_ response: Any?) { |
| 34 | + guard let dict = response as? [String:Any] else { return nil } |
| 35 | + guard let userId = dict["userId"] as? Int, |
| 36 | + let id = dict["id"] as? Int, |
| 37 | + let title = dict["title"] as? String, |
| 38 | + let completed = dict["completed"] as? Bool else { return nil } |
| 39 | + |
| 40 | + self.userId = userId |
| 41 | + self.id = id |
| 42 | + self.title = title |
| 43 | + self.completed = completed |
| 44 | + super.init(response) |
| 45 | + } |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | + |
| 50 | +Or using data, for instance image, can be created by the data response: |
| 51 | + |
| 52 | +```swift |
| 53 | +/// Initializes object from Data. |
| 54 | +class ExampleImageObject: ResponseBodyParsable { |
| 55 | + |
| 56 | + var image: UIImage |
| 57 | + |
| 58 | + required init?(_ data: Data) { |
| 59 | + guard let image = UIImage(data: data) else { |
| 60 | + return nil |
| 61 | + } |
| 62 | + |
| 63 | + self.image = image |
| 64 | + super.init(data) |
| 65 | + } |
| 66 | + |
| 67 | + required init?(_ response: Any?) { |
| 68 | + return nil |
| 69 | + } |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +### Creating an API configuration |
| 74 | + |
| 75 | +Using highly customizable `APIConfiguration` object, API requests can be defined easily and requests from Network Layer. |
| 76 | + |
| 77 | +In below example, uses `ExampleResponseObject` as a response model to create API configuration with basic parameters. |
| 78 | + |
| 79 | +```swift |
| 80 | +let api = APIConfiguration(hostURL: "https://jsonplaceholder.typicode.com", |
| 81 | + endPoint: "todos/1", |
| 82 | + responseBodyObject: ExampleResponseObject.self) |
| 83 | + |
| 84 | +``` |
| 85 | + |
| 86 | +Or, advanced parameters can be applied. |
| 87 | + |
| 88 | +```swift |
| 89 | +let api = APIConfiguration(hostURL: "https://jsonplaceholder.typicode.com", |
| 90 | + endPoint: "todos/1", |
| 91 | + requestType: .get, |
| 92 | + headers: nil, body: nil, |
| 93 | + responseBodyObject: ExampleResponseObject.self, |
| 94 | + priority: .low, |
| 95 | + cachingTime: .init(seconds: 60), |
| 96 | + isMainOperation: false, autoCache: false) |
| 97 | + |
| 98 | +``` |
| 99 | + |
| 100 | +### Requesting API from Network Layer |
| 101 | + |
| 102 | +When operation is completed, completion block will return with two cases, whether error or successful response. |
| 103 | + |
| 104 | +```swift |
| 105 | +guard let apiReq = api else { |
| 106 | + print("Something wrong with the configuration") |
| 107 | + return |
| 108 | +} |
| 109 | + |
| 110 | +apiReq.request { (result) in |
| 111 | + switch result { |
| 112 | + case .error(let errResponse): |
| 113 | + print("Error: \(errResponse.error.localizedDescription)") |
| 114 | + case .success(let successfulResponse): |
| 115 | + print("Response Body: \(successfulResponse.responseBody)") |
| 116 | + } |
| 117 | +} |
| 118 | +``` |
| 119 | + |
| 120 | +## Advanced Usage |
| 121 | + |
| 122 | +### Defining AutoCache |
| 123 | +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. |
| 124 | + |
| 125 | +In below, same example object overrides the method and uses, for instance one of the variables in the response to define caching expiry. |
| 126 | + |
| 127 | +```swift |
| 128 | +/// Initializes object from JSON response. |
| 129 | +class ExampleResponseObject: ResponseBodyParsable { |
| 130 | + |
| 131 | + var userId: Int |
| 132 | + var id: Int |
| 133 | + var title: String |
| 134 | + var completed: Bool |
| 135 | + var expiry: Date? |
| 136 | + |
| 137 | + required init?(_ data: Data) { |
| 138 | + return nil |
| 139 | + } |
| 140 | + |
| 141 | + required init?(_ response: Any?) { |
| 142 | + guard let dict = response as? [String:Any] else { return nil } |
| 143 | + guard let userId = dict["userId"] as? Int, |
| 144 | + let id = dict["id"] as? Int, |
| 145 | + let title = dict["title"] as? String, |
| 146 | + let completed = dict["completed"] as? Bool else { return nil } |
| 147 | + |
| 148 | + self.userId = userId |
| 149 | + self.id = id |
| 150 | + self.title = title |
| 151 | + self.completed = completed |
| 152 | + |
| 153 | + // gets expiry value from the response |
| 154 | + self.expiry = dict["expiry"] as? Date |
| 155 | + |
| 156 | + super.init(response) |
| 157 | + } |
| 158 | + |
| 159 | + override func cachingEndsAt() -> Date? { |
| 160 | + return self.expiry |
| 161 | + } |
| 162 | +} |
| 163 | +``` |
| 164 | +Then, in the API configuration, `autoCache` parameter should be set to `true`. |
| 165 | + |
| 166 | +### Operation Queues and priority of the requests |
| 167 | +`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. |
| 168 | + |
| 169 | +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. |
0 commit comments