|
1 | 1 | # WebServiceSwift |
2 | | -Wrapper for working with network. |
| 2 | + |
| 3 | +[](http://cocoapods.org/pods/WebServiceSwift) |
| 4 | +[](https://github.com/ProVir/WebServiceSwift) |
| 5 | +[](http://cocoapods.org/pods/WebServiceSwift) |
| 6 | +[](https://github.com/ProVir/WebServiceSwift/blob/master/LICENSE) |
| 7 | + |
| 8 | +Wrapper for working with network. Support Swift 3.0 - 4.0 |
| 9 | + |
| 10 | +- [Features](#features) |
| 11 | +- [Requirements](#requirements) |
| 12 | +- [Communication](#communication) |
| 13 | +- [Installation](#installation) |
| 14 | +- [Usage (English / Русский)](#usage-english--%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9) |
| 15 | +- [Author](#author) |
| 16 | +- [License](#license) |
| 17 | + |
| 18 | + |
| 19 | + |
| 20 | +## Features |
| 21 | + |
| 22 | +- [x] Easy interface for work |
| 23 | +- [x] All work with network in inner engine and storage, hided from interface. |
| 24 | +- [x] Support Dispatch Queue. |
| 25 | +- [x] One class work with many types requests. |
| 26 | +- [x] One class work with many engines and storages. |
| 27 | +- [x] Simple storage on disk in package. Easy - add only engine and work! |
| 28 | +- [ ] Support work with NetworkActivityIndicator on iOS. |
| 29 | +- [ ] Simple HTTP Engine. |
| 30 | + |
| 31 | + |
| 32 | +## Requirements |
| 33 | + |
| 34 | +- iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+ |
| 35 | +- Xcode 8.1, 8.2, 8.3, and 9.0 |
| 36 | +- Swift 3.0, 3.1, 3.2, and 4.0 |
| 37 | + |
| 38 | + |
| 39 | +## Communication |
| 40 | + |
| 41 | +- If you **need help**, go to [provir.ru](http://provir.ru) |
| 42 | +- If you **found a bug**, open an issue. |
| 43 | +- If you **have a feature request**, open an issue. |
| 44 | +- If you **want to contribute**, submit a pull request. |
| 45 | + |
| 46 | + |
| 47 | + |
| 48 | +## Installation |
| 49 | + |
| 50 | +### CocoaPods |
| 51 | + |
| 52 | +[CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: |
| 53 | + |
| 54 | +```bash |
| 55 | +$ gem install cocoapods |
| 56 | +``` |
| 57 | + |
| 58 | +> CocoaPods 1.1.0+ is required to build WebServiceSwift 2.1.0+. |
| 59 | +
|
| 60 | +To integrate WebServiceSwift into your Xcode project using CocoaPods, specify it in your `Podfile`: |
| 61 | + |
| 62 | +```ruby |
| 63 | +source 'https://github.com/CocoaPods/Specs.git' |
| 64 | +platform :ios, '8.0' |
| 65 | +use_frameworks! |
| 66 | + |
| 67 | +target '<Your Target Name>' do |
| 68 | + pod 'WebServiceSwift', '~> 2.1' |
| 69 | +end |
| 70 | +``` |
| 71 | + |
| 72 | +Then, run the following command: |
| 73 | + |
| 74 | +```bash |
| 75 | +$ pod install |
| 76 | +``` |
| 77 | + |
| 78 | +### Carthage |
| 79 | + |
| 80 | +[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. |
| 81 | + |
| 82 | +You can install Carthage with [Homebrew](http://brew.sh/) using the following command: |
| 83 | + |
| 84 | +```bash |
| 85 | +$ brew update |
| 86 | +$ brew install carthage |
| 87 | +``` |
| 88 | + |
| 89 | +To integrate WebServiceSwift into your Xcode project using Carthage, specify it in your `Cartfile`: |
| 90 | + |
| 91 | +```ogdl |
| 92 | +github "ProVir/WebServiceSwift" ~> 2.1 |
| 93 | +``` |
| 94 | + |
| 95 | +Run `carthage update` to build the framework and drag the built `WebServiceSwift.framework` into your Xcode project. |
| 96 | + |
| 97 | +### Swift Package Manager |
| 98 | + |
| 99 | +The [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. It is in early development, but WebServiceSwift does support its use on supported platforms. |
| 100 | + |
| 101 | +Once you have your Swift package set up, adding WebServiceSwift as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`. |
| 102 | + |
| 103 | +```swift |
| 104 | +dependencies: [ |
| 105 | + .Package(url: "https://github.com/ProVir/WebServiceSwift.git", majorVersion: 2) |
| 106 | +] |
| 107 | +``` |
| 108 | + |
| 109 | +### Manually |
| 110 | + |
| 111 | +If you prefer not to use any of the aforementioned dependency managers, you can integrate WebServiceSwift into your project manually. |
| 112 | + |
| 113 | +Copy files from directory `Source` in your project. |
| 114 | + |
| 115 | + |
| 116 | +--- |
| 117 | + |
| 118 | +## Usage (English / Русский) |
| 119 | + |
| 120 | +To use the library, you need: |
| 121 | +1. Create at least one type of request that implements the `WebServiceRequesting` protocol. |
| 122 | +2. Create at least one class for work with the network (engine), implementing the protocol `WebServiceEngining`. |
| 123 | +3. If desired, you can create a class for storing hashes or use the existing one - `WebServiceSimpleStore`. |
| 124 | +4. Write a factory to generate a WebService object or write an extension for it with a convenience constructor. |
| 125 | + |
| 126 | +**Note:** To use the library, remember to include it in each file: `import WebService`. |
| 127 | + |
| 128 | +The project has a less abstract example of using the library, which can be downloaded separately. |
| 129 | + |
| 130 | +# |
| 131 | + |
| 132 | +Для использования библиотеки вам нужно: |
| 133 | +1. Создать как минимум один тип запроса, реализующий протокол `WebServiceRequesting`. |
| 134 | +2. Создать как минимум один класс для работ с сетью, реализующий протокол `WebServiceEngining`. |
| 135 | +3. По желанию можно создать класс для хранения хешей или использовать существующий - `WebServiceSimpleStore`. |
| 136 | +4. Написать метод - фабрику для генерации объекта `WebService` или написать для него расширение с конструктором, вызывающий базовый конструктор с параметрами. |
| 137 | + |
| 138 | +**Замечание:** для использования библиотеки не забудьте ее подключить в каждом файле: `import WebService`. |
| 139 | + |
| 140 | +В проекте есть менее абстрактный пример использования библиотеки, который можно скачать отдельно. |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | +#### An example request structure: |
| 145 | + |
| 146 | +```swift |
| 147 | +struct RequestMethod: WebServiceRequesting { |
| 148 | + let method:WebServiceMethod |
| 149 | + let requestKey:AnyHashable? |
| 150 | + |
| 151 | + init(requestKey:AnyHashable? = nil, method:WebServiceMethod) { |
| 152 | + self.requestKey = requestKey |
| 153 | + self.method = method |
| 154 | + } |
| 155 | +} |
| 156 | + |
| 157 | +enum WebServiceMethod { |
| 158 | + case method1(ParamType1, param2:ParamType2) |
| 159 | + case method2(ParamType1) |
| 160 | + case method3 |
| 161 | +} |
| 162 | + |
| 163 | +``` |
| 164 | + |
| 165 | +Such types of requests can be as many as you like and for each one you can use your own class - the engine. There can also be several versions of the storage. |
| 166 | + |
| 167 | +Таких типов запросов может быть сколько угодно и для каждого можно использовать свой класс - движок (engine). Разновидностей хранилища тоже может быть несколько. |
| 168 | + |
| 169 | + |
| 170 | + |
| 171 | +#### Example of a class for working with a network using a library [Alamofire](https://github.com/Alamofire/Alamofire): |
| 172 | + |
| 173 | +```swift |
| 174 | +class WebServiceEngine: WebServiceEngining { |
| 175 | + |
| 176 | + let queueForRequest:DispatchQueue? = nil |
| 177 | + let queueForDataHandler:DispatchQueue? = nil |
| 178 | + let queueForDataHandlerFromStorage:DispatchQueue? = DispatchQueue.global(qos: .default) |
| 179 | + |
| 180 | + |
| 181 | + func isSupportedRequest(_ request: WebServiceRequesting, rawDataForRestoreFromStorage: Any?) -> Bool { |
| 182 | + return request is RequestMethod |
| 183 | + } |
| 184 | + |
| 185 | + |
| 186 | + func request(requestId:UInt64, request:WebServiceRequesting, |
| 187 | + completionWithData:@escaping (_ data:Any) -> Void, |
| 188 | + completionWithError:@escaping (_ error:Error) -> Void, |
| 189 | + canceled:@escaping () -> Void) { |
| 190 | + |
| 191 | + guard let method = (request as? RequestMethod)?.method else { |
| 192 | + completionWithError(WebServiceRequestError.notSupportRequest) |
| 193 | + return |
| 194 | + } |
| 195 | + |
| 196 | + //Custom method without example |
| 197 | + var url = urlFromMethod(method) |
| 198 | + |
| 199 | + Alamofire.request(method.url).responseData { response in |
| 200 | + switch response.result { |
| 201 | + case .success(let data): |
| 202 | + completionWithData(data) |
| 203 | + |
| 204 | + case .failure(let error): |
| 205 | + completionWithError(error) |
| 206 | + } |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + |
| 211 | + func cancelRequest(requestId: UInt64) { |
| 212 | + |
| 213 | + } |
| 214 | + |
| 215 | + |
| 216 | + func dataHandler(request:WebServiceRequesting, data:Any, isRawFromStorage:Bool) throws -> Any? { |
| 217 | + guard request is RequestMethod, let data = data as? Data else { |
| 218 | + throw WebServiceRequestError.notSupportDataHandler |
| 219 | + } |
| 220 | + |
| 221 | + return String(data: data, encoding: .utf8) ?? String(data: data, encoding: .windowsCP1251) |
| 222 | + } |
| 223 | + |
| 224 | +} |
| 225 | +``` |
| 226 | + |
| 227 | +Working with the network is not a prerequisite for the engine. Behind this layer, you can hide the work with the database or at least temporarily put a stub. On the interface side, this is not important and during the development of the engine can be unnoticeably replaced, without changing the code of the requests themselves (provided that the type of data returned does not change). |
| 228 | + |
| 229 | + |
| 230 | +Вовсе не обязательно движок (engine) должен работать с сетью. За этим слоем вы можете скрыть работу с БД или вовсе временно выставить заглушку. Со стороны интерфейса это не важно и в процессе разработки движки можно незаметно подменять, не меняя код самих запросов (при условии что тип возвращаемых данных не меняется). |
| 231 | + |
| 232 | + |
| 233 | +#### WebService Factory example: |
| 234 | + |
| 235 | +```swift |
| 236 | +extension WebService { |
| 237 | + |
| 238 | + convenience init(delegate:WebServiceDelegate? = nil) { |
| 239 | + let engine = WebServiceEngine() |
| 240 | + |
| 241 | + var storages:[WebServiceStoraging] = [] |
| 242 | + if let storage = WebServiceSimpleStore() { |
| 243 | + storages.append(storage) |
| 244 | + } |
| 245 | + |
| 246 | + self.init(engines: [engine], storages:storages) |
| 247 | + |
| 248 | + self.delegate = delegate |
| 249 | + } |
| 250 | +} |
| 251 | +``` |
| 252 | + |
| 253 | +You can also make support for a singleton - an example of this approach is in the source code. |
| 254 | + |
| 255 | +Также можно сделать поддержку синглетона - пример такого подхода есть в исходниках. |
| 256 | + |
| 257 | + |
| 258 | +#### An example of using the closure and without reading the hash from the disk: |
| 259 | + |
| 260 | +```swift |
| 261 | +let webService = WebService() |
| 262 | + |
| 263 | +webService.request(RequestMethod(method: .method1(val1, param2: val2))) { response in |
| 264 | + switch response { |
| 265 | + case .canceledRequest, .duplicateRequest: |
| 266 | + break |
| 267 | + |
| 268 | + case .data(let dataCustomType): |
| 269 | + dataFromServer = dataCustomType |
| 270 | + |
| 271 | + case .error(let error): |
| 272 | + showError(error) |
| 273 | + |
| 274 | + } |
| 275 | + } |
| 276 | +``` |
| 277 | + |
| 278 | +We pass the data in request, on the output we get the ready object for display. |
| 279 | + |
| 280 | +Передаем данные в запросе, на выходе получаем готовый объект для отображения. |
| 281 | + |
| 282 | + |
| 283 | + |
| 284 | +#### An example using a delegate and reading a hash from disk: |
| 285 | + |
| 286 | +```swift |
| 287 | +let webService = WebService(delegate:self) |
| 288 | + |
| 289 | +webService.request(RequestMethod(method: .method2(val1)), includeResponseStorage: true) |
| 290 | + |
| 291 | +func webServiceResponse(request: WebServiceRequesting, isStorageRequest: Bool, response: WebServiceResponse) { |
| 292 | + switch response { |
| 293 | + case .canceledRequest, .duplicateRequest: |
| 294 | + break |
| 295 | + |
| 296 | + case .data(let dataCustomType): |
| 297 | + if isStorageRequest { |
| 298 | + dataFromStorage = dataCustomType |
| 299 | + } else { |
| 300 | + dataFromServer = dataCustomType |
| 301 | + } |
| 302 | + |
| 303 | + case .error(let error): |
| 304 | + showError(error) |
| 305 | + |
| 306 | + } |
| 307 | +} |
| 308 | +``` |
| 309 | + |
| 310 | +If data from the disk is received earlier than from the network, or there will be an error in retrieving data from the network - hashed data will return to the delegate (`isStorageRequest = true`), otherwise only data from the network will be received. |
| 311 | + |
| 312 | +Если данные с диска будут получены раньше, чем с сети, либо произойдет ошибка получения данных с сети - хешированные данные вернутся в делегат (`isStorageRequest = true`), иначе будут получены данные только с сети. |
| 313 | + |
| 314 | + |
| 315 | +#### Example of requesting hash data without requesting a server: |
| 316 | + |
| 317 | +```swift |
| 318 | +let webService = WebService() |
| 319 | + |
| 320 | +webService.requestReadStorage(RequestMethod(.method3)) { response in |
| 321 | + switch response { |
| 322 | + case .canceledRequest, .duplicateRequest: |
| 323 | + break |
| 324 | + |
| 325 | + case .data(let dataCustomType): |
| 326 | + dataFromStorage = dataCustomType |
| 327 | + |
| 328 | + case .error(let error): |
| 329 | + showError(error) |
| 330 | + |
| 331 | + } |
| 332 | + } |
| 333 | +``` |
| 334 | + |
| 335 | +You can also request data from the storage. In case of a reading error, you will be able to find out the reason. Enums `.canceledRequest` and `.duplicateRequest` will never be returned. |
| 336 | + |
| 337 | +Также можно отдельно запросить данные с хеша. В случае ошибки чтения можно будет узнать причину. Значения `.canceledRequest` и `.duplicateRequest` никогда не будут возвращены. |
| 338 | + |
| 339 | + |
| 340 | + |
| 341 | + |
| 342 | +## Author |
| 343 | + |
| 344 | +[**ViR (Короткий Виталий)**](http://provir.ru) |
| 345 | + |
| 346 | + |
| 347 | +## License |
| 348 | + |
| 349 | +WebServiceSwift is released under the MIT license. [See LICENSE](https://github.com/ProVir/WebServiceSwift/blob/master/LICENSE) for details. |
| 350 | + |
| 351 | + |
0 commit comments