├── .swift-version ├── .gitignore ├── raccoon.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcshareddata │ └── xcschemes │ │ └── Raccoon.xcscheme └── project.pbxproj ├── raccoon.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── raccoon.xcscmblueprint ├── Podfile ├── raccoon ├── Raccoon.h ├── Info.plist └── source │ ├── Endpoint.swift │ └── Client.swift ├── raccoonTests └── Info.plist ├── Raccoon.podspec ├── CHANGELOG.md ├── LICENSE ├── Podfile.lock └── README.md /.swift-version: -------------------------------------------------------------------------------- 1 | 4.2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Pods 2 | raccoon.xcodeproj/xcuserdata 3 | raccoon.xcworkspace/xcuserdata 4 | -------------------------------------------------------------------------------- /raccoon.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /raccoon.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /raccoon.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '9.0' 2 | use_frameworks! 3 | 4 | abstract_target 'abstract_target' do 5 | 6 | pod 'AlamofireCoreData', '~> 2.0' 7 | pod 'PromiseKit/CorePromise', '~> 4.4' 8 | 9 | target 'Raccoon' 10 | 11 | target 'RaccoonTests' do 12 | pod 'OHHTTPStubs', '~> 5.2' 13 | pod 'OHHTTPStubs/Swift', '~> 5.2' 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /raccoon/Raccoon.h: -------------------------------------------------------------------------------- 1 | // 2 | // Raccoon.h 3 | // Raccoon 4 | // 5 | // Created by Manu on 26/4/16. 6 | // Copyright © 2016 manuege. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Raccoon. 12 | FOUNDATION_EXPORT double RaccoonVersionNumber; 13 | 14 | //! Project version string for Raccoon. 15 | FOUNDATION_EXPORT const unsigned char RaccoonVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /raccoonTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /raccoon/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Raccoon.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | 3 | spec.name = "Raccoon" 4 | spec.version = "1.3.0" 5 | spec.summary = "Puts together Alamofire, CoreData and PromiseKit" 6 | spec.description = <<-DESC 7 | A nice set of protocols and tools that puts together Alamofire, PromiseKit and CoreData. 8 | DESC 9 | spec.homepage = "https://github.com/ManueGE/Raccoon/" 10 | spec.license = "MIT" 11 | 12 | 13 | spec.author = "Manuel García-Estañ" 14 | spec.social_media_url = "http://twitter.com/ManueGE" 15 | 16 | spec.platform = :ios, "9.0" 17 | spec.source = { :git => "https://github.com/ManueGE/Raccoon.git", :tag => "#{spec.version}" } 18 | 19 | spec.requires_arc = true 20 | spec.dependency "Alamofire", "~> 4.7" 21 | spec.dependency "PromiseKit/CorePromise", "~> 4.4" 22 | spec.dependency "AlamofireCoreData", "~> 2.0" 23 | 24 | spec.source_files = "Raccoon/source/**/*.{swift}" 25 | 26 | spec.framework = "CoreData" 27 | 28 | end 29 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ### 1.3.0 (25 September 2018) 4 | - Swift 4.2, Alamofire 4.7 5 | 6 | ### 1.2.0 (10 October 2017) 7 | - Swift 4, Alamofire 4.5, PromiseKit 4.4 8 | 9 | ## 1.1.1 (30 June 2017) 10 | - Fix build problem with `void` promises in swift 4. 11 | 12 | ## 1.1.0 (30 June 2017) 13 | - Add `cancellableEnqueue` methods to allow cancel requests manually. 14 | - Swift 3, Alamofire 4.5, PromiseKit 4.2, Groot 2.0. 15 | 16 | ## 1.0.0 (13 October 2016) 17 | - First stable version 18 | - Remove Realm support 19 | - Remove all serliaziation code. It is now in a separate pod ([AlamofireCoreData](http://github.com/manueGE/AlamofireCoreData)) 20 | - Swift 3, Alamofire 4.0, PromiseKit 4.0, Groot 2.0. 21 | 22 | ## Betas 0.x.x 23 | 24 | ### 0.2.0 25 | #### Enhacements 26 | - Support serializing as an array of `Wrapper` instances. 27 | 28 | #### Breaking changes 29 | - New `ReponseConverter` input and output parameters. 30 | 31 | ### 0.1.1 32 | - Supports `PromiseKit` latest version (3.2) 33 | 34 | ### 0.1.0 35 | - Initial version 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Manuel García-Estañ 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /raccoon/source/Endpoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Endpoint.swift 3 | // raccoon 4 | // 5 | // Created by Manuel García-Estañ on 8/10/16. 6 | // Copyright © 2016 manuege. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | 12 | /** 13 | Helper extension to build URLS from base URL string and path 14 | */ 15 | public extension URL { 16 | 17 | /** 18 | Creates a new URL with the given base and path. 19 | Internally it make use of `init(string: String, relativeTo: URL)` so same rules applies here. 20 | */ 21 | init?(base: String, path: String) { 22 | guard let baseURL = URL(string: base) else { 23 | return nil 24 | } 25 | 26 | self.init(string: path, relativeTo: baseURL) 27 | } 28 | } 29 | 30 | /* An Endpoint is just an instance that can build a `DataRequest` from a base url. 31 | Use it to enqueue request in a client 32 | */ 33 | public protocol Endpoint { 34 | 35 | /** 36 | Returns a request built with the given base url 37 | 38 | - parameter baseURL: The base url to build the request 39 | 40 | - returns: The request ready to be sent. 41 | */ 42 | func request(withBaseURL baseURL: String) -> DataRequest 43 | } 44 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (4.7.3) 3 | - AlamofireCoreData (2.0.0): 4 | - Alamofire (~> 4.7) 5 | - Groot (~> 3.0) 6 | - Groot (3.0.1): 7 | - Groot/Swift (= 3.0.1) 8 | - Groot/Swift (3.0.1) 9 | - OHHTTPStubs (5.2.1): 10 | - OHHTTPStubs/Default (= 5.2.1) 11 | - OHHTTPStubs/Core (5.2.1) 12 | - OHHTTPStubs/Default (5.2.1): 13 | - OHHTTPStubs/Core 14 | - OHHTTPStubs/JSON 15 | - OHHTTPStubs/NSURLSession 16 | - OHHTTPStubs/OHPathHelpers 17 | - OHHTTPStubs/JSON (5.2.1): 18 | - OHHTTPStubs/Core 19 | - OHHTTPStubs/NSURLSession (5.2.1): 20 | - OHHTTPStubs/Core 21 | - OHHTTPStubs/OHPathHelpers (5.2.1) 22 | - OHHTTPStubs/Swift (5.2.1): 23 | - OHHTTPStubs/Core 24 | - PromiseKit/CorePromise (4.4.0) 25 | 26 | DEPENDENCIES: 27 | - AlamofireCoreData (~> 2.0) 28 | - OHHTTPStubs (~> 5.2) 29 | - OHHTTPStubs/Swift (~> 5.2) 30 | - PromiseKit/CorePromise (~> 4.4) 31 | 32 | SPEC REPOS: 33 | https://github.com/cocoapods/specs.git: 34 | - Alamofire 35 | - AlamofireCoreData 36 | - Groot 37 | - OHHTTPStubs 38 | - PromiseKit 39 | 40 | SPEC CHECKSUMS: 41 | Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568 42 | AlamofireCoreData: 3205949bd789c2aa5e1cd8f4d703631c9d7ba09c 43 | Groot: a668afbcf0be88d76c0a26c714cfa4638ceaca66 44 | OHHTTPStubs: 3a42f25c00563b71355ac73112ba2324e9e6cef4 45 | PromiseKit: ecf5fe92275d57ee77c9ede858af47a162e9b97e 46 | 47 | PODFILE CHECKSUM: 5b5606354902ff60b7df1b19866ff037d347e788 48 | 49 | COCOAPODS: 1.5.3 50 | -------------------------------------------------------------------------------- /raccoon.xcworkspace/xcshareddata/raccoon.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "281CF20BD3701CFD2C39EA9F59F9FFC7E4BC3EFD", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "281CF20BD3701CFD2C39EA9F59F9FFC7E4BC3EFD" : 9223372036854775807, 8 | "619A3FBBE13EC7937545FB26C1C97E17658B1AE8" : 9223372036854775807 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "877C6854-1300-4599-8397-824BA41E7380", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "281CF20BD3701CFD2C39EA9F59F9FFC7E4BC3EFD" : "raccoon\/", 13 | "619A3FBBE13EC7937545FB26C1C97E17658B1AE8" : "..\/AlamofireCoreData" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "raccoon", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "raccoon.xcworkspace", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/ManueGE\/Raccoon.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "281CF20BD3701CFD2C39EA9F59F9FFC7E4BC3EFD" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/ManueGE\/AlamofireCoreData.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "619A3FBBE13EC7937545FB26C1C97E17658B1AE8" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /raccoon.xcodeproj/xcshareddata/xcschemes/Raccoon.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /raccoon/source/Client.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Client.swift 3 | // raccoon 4 | // 5 | // Created by Manuel García-Estañ on 8/10/16. 6 | // Copyright © 2016 manuege. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreData 11 | import AlamofireCoreData 12 | import PromiseKit 13 | import Alamofire 14 | 15 | /** 16 | An object which encapsulate a promise that can be cancelled at any time. 17 | */ 18 | public struct Cancellable { 19 | /// The promise of the cancellable object 20 | public let promise: Promise 21 | 22 | /// The method to call if the request must be cancelled 23 | public let cancel: () -> Void 24 | } 25 | 26 | /** 27 | Clients are instances that can send network requests. The requests are built using `Endpoints`. 28 | The responses of this endpoints will be inserted in the given managed object context. 29 | */ 30 | public protocol Client { 31 | 32 | // MARK: Required 33 | 34 | /// The base url which will be used to build the reqeusts 35 | var baseURL: String { get } 36 | 37 | /// The managed object context where all the responses will be inserted. 38 | var context: NSManagedObjectContext { get } 39 | 40 | // MARK: Optionals 41 | /** 42 | The DataResponseSerializer which will transform the original response to the JSON which will be used to insert the responses. 43 | By default it is `DataRequest.jsonResponseSerializer()` 44 | */ 45 | var jsonSerializer: DataResponseSerializer { get } 46 | 47 | /** 48 | Use this method to perform any last minute changes on the DataRequest to send. 49 | Here you can add some validations, log the requests, or whatever thing you need. 50 | By default, it returns the request itself, without any addition 51 | 52 | - parameter request: The request that will be sent 53 | - parameter endpoint: The endpoint which launched the reqeust 54 | 55 | - returns: the modified request 56 | */ 57 | func prepare(_ request: DataRequest, for endpoint: Endpoint) -> DataRequest 58 | 59 | /** 60 | Use this method to perform any last minute changes on the Promise created when a request is sent. 61 | Here you can add some common `recover` or `then` to all the promise 62 | By default, it returns the promise itself, without any addition 63 | 64 | - parameter request: The `Promise` 65 | - parameter endpoint: The `Endpoint` that launched the request 66 | 67 | - returns: the modified request 68 | */ 69 | func process(_ promise: Promise, for endpoint: Endpoint) -> Promise 70 | } 71 | 72 | public extension Client { 73 | 74 | // MARK: - Default methods 75 | public var jsonSerializer: DataResponseSerializer { 76 | return DataRequest.jsonResponseSerializer() 77 | } 78 | 79 | public func prepare(_ request: DataRequest, for endpoint: Endpoint) -> DataRequest { 80 | return request 81 | } 82 | 83 | func process(_ promise: Promise, for endpoint: Endpoint) -> Promise { 84 | return promise 85 | } 86 | } 87 | 88 | public extension Client { 89 | 90 | /** 91 | Enqueues the request generated by the endpoint and insert it using the generic type. 92 | It returns a Cancellable to inform if the request has finished succesfully or not. 93 | 94 | The request can be cancelled at any time by calling `cancel()` in the cancellable object. 95 | 96 | - parameter endpoint: The endpoint 97 | 98 | - returns: The Cancellable object 99 | */ 100 | public func cancellableEnqueue(_ endpoint: Endpoint) -> Cancellable { 101 | let request = endpoint.request(withBaseURL: baseURL) 102 | let promise = Promise { fulfill, reject in 103 | prepare(request, for: endpoint) 104 | .responseInsert( 105 | queue: nil, 106 | jsonSerializer: jsonSerializer, 107 | context: context, 108 | type: T.self) { response in 109 | 110 | switch response.result { 111 | case let .success(value): 112 | fulfill(value) 113 | case let .failure(error): 114 | reject(error) 115 | } 116 | } 117 | } 118 | 119 | let finalPromise = process(promise, for: endpoint) 120 | let cancel = request.cancel 121 | return Cancellable(promise: finalPromise, cancel: cancel) 122 | } 123 | 124 | /** 125 | Enqueues the request generated by the endpoint and insert it using the generic type. 126 | It returns a Promise to inform if the request has finished succesfully or not 127 | 128 | - parameter endpoint: The endpoint 129 | 130 | - returns: The promise 131 | */ 132 | public func enqueue(_ endpoint: Endpoint) -> Promise { 133 | return cancellableEnqueue(endpoint).promise 134 | } 135 | 136 | /** 137 | Enqueues the request generated by the endpoint. 138 | It returns a Cancellable to inform if the request has finished succesfully or not 139 | 140 | The request can be cancelled at any time by calling `cancel()` in the cancellable object. 141 | 142 | - parameter endpoint: The endpoint 143 | 144 | - returns: The cancellable object 145 | */ 146 | public func cancellableEnqueue(_ endpoint: Endpoint) -> Cancellable { 147 | let request = endpoint.request(withBaseURL: baseURL) 148 | let promise = Promise { fulfill, reject in 149 | prepare(request, for: endpoint) 150 | .responseInsert( 151 | jsonSerializer: jsonSerializer, 152 | context: context, 153 | type: Empty.self) { response in 154 | 155 | switch response.result { 156 | case .success: 157 | fulfill(()) 158 | case let .failure(error): 159 | reject(error) 160 | } 161 | } 162 | } 163 | 164 | let finalPromise = process(promise, for: endpoint) 165 | let cancel = request.cancel 166 | return Cancellable(promise: finalPromise, cancel: cancel) 167 | } 168 | 169 | /** 170 | Enqueues the request generated by the endpoint. 171 | It returns an empty promise to inform if the request has finished succesfully or not 172 | 173 | - parameter endpoint: The endpoint 174 | 175 | - returns: The promise 176 | */ 177 | public func enqueue(_ endpoint: Endpoint) -> Promise { 178 | return cancellableEnqueue(endpoint).promise 179 | } 180 | } 181 | 182 | private struct Empty {} 183 | extension Empty: Insertable { 184 | public static func insert(from json: Any, in context: NSManagedObjectContext) throws -> Empty { 185 | return Empty() 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raccoon 2 | 3 | **Raccoon** is a set of protocols and tools that puts together [**Alamofire**](https://github.com/Alamofire/Alamofire), [**PromiseKit**](https://github.com/mxcl/PromiseKit) and **CoreData**. 4 | 5 | Internally, Raccoon uses [**Groot**](https://github.com/gonzalezreal/Groot) and [**AlamofireCoreData**](https://github.com/ManueGE/AlamofireCoreData) to serialize JSON into the CoreData objects, so you will need to be familiar with these libraries. 6 | 7 | Raccoon is built around: 8 | 9 | - **Alamofire 4.0.x** 10 | - **PromiseKit 4.0.x** 11 | - **Groot 2.0.x** 12 | - **AlamofireCoreData 1.0.x** 13 | 14 | With Raccoon you'll be able to perform HTTP request as easy as this: 15 | 16 | ````swift 17 | let client = Client(context: context) 18 | client.enqueue(userEndpoint) 19 | .then { (user: User) in 20 | print(user) // At this point, your user is already inserted in your context 21 | } 22 | .catch { error in 23 | print(error) 24 | } 25 | ```` 26 | 27 | ## Installing Raccoon 28 | 29 | ### Using CocoaPods 30 | 31 | Add the following line to your `Podfile`: 32 | 33 | ````ruby 34 | pod 'Raccoon' 35 | ```` 36 | 37 | Then run `$ pod install`. 38 | 39 | And finally, in the files where you need **Raccoon**: 40 | 41 | ````swift 42 | import Raccoon 43 | ```` 44 | 45 | If you don’t have CocoaPods installed or integrated into your project, you can learn how to do so [here](http://cocoapods.org). 46 | 47 | - 48 | 49 | # Usage 50 | 51 | ## Intro 52 | 53 | Raccoon basically consist in two protocols, `Client` and `Endpoint`. 54 | 55 | - `Client` instances are responsible to enqueue http request and return them in the shape of promises. Clients need, at least, a base url (to build the requests) and a `NSManagedObjectContext` where the responses will be inserted. 56 | - `Endpoint` instances are objects that provides information to build the request that will be sent by the clients. Endpoints just must implement one method, `request(withBaseURL:)` which will return the full request built with the given base url. 57 | 58 | Before being ready to work with Raccoon, you should be familiar with: 59 | 60 | - [**PromiseKit**](https://github.com/mxcl/PromiseKit): At least, you should be familiar with basic `Promise` handling: `then`, `catch`, `recover` 61 | - [**Groot**](https://github.com/gonzalezreal/Groot): It is used to serialize JSON into CoreData, so your entities must fullfill its requirements. 62 | - [**AlamofireCoreData**](https://github.com/ManueGE/AlamofireCoreData): At least, you should read about `Wrapper` (to serialize `NSManagedObject` instances from bigger JSONs) and `Many` (to serialize an array of objects). 63 | 64 | 65 | 66 | ## Getting started 67 | 68 | To explain how use Raccoon, we are going to build a simple example. 69 | 70 | Let's suppose we have an API with 2 methods: 71 | 72 | - `GET http://sampleapi.com/users/`: Get a list of users. 73 | - `GET http://sampleapi.com/users//`: Get the detail of the given user. 74 | 75 | We also have to add an api key as a header in the requests. 76 | 77 | To modelize the response, we have our `NSManagedObject` subclass called `User` which has been prepared to being serialized using [**Groot**](https://github.com/gonzalezreal/Groot). 78 | 79 | ### Creating the client 80 | 81 | The `Client` protocol has two required fields: 82 | 83 | - `context: NSManagedObjectContext`: The context used to insert the responses. 84 | - `baseURL: String`: The base url of the api. 85 | 86 | So, we will create our own `Client` class conforming this protocol: 87 | 88 | ````swift 89 | 90 | import Raccoon 91 | 92 | final class Client: Raccoon.Client { 93 | 94 | let baseURL: String = "http://sampleapi.com/" 95 | let context: NSManagedObjectContext 96 | 97 | init(context: NSManagedObjectContext) { 98 | self.context = context 99 | } 100 | } 101 | ```` 102 | 103 | That's all, now we can create a client by doing: 104 | 105 | ````swift 106 | let client = Client(context: aContext) 107 | ```` 108 | 109 | ### Creating the endpoint 110 | 111 | The `Endpoint` protocol just have one method: 112 | 113 | ````swift 114 | func request(withBaseURL baseURL: String) -> DataRequest 115 | ```` 116 | 117 | which is called from the client to build the request. 118 | 119 | In our example, we will create a `Endpoint` subprotocol to helping us to build the actual endpoints: 120 | 121 | ````swift 122 | protocol AppEndpoint: Endpoint { 123 | var path: String { get } 124 | var method: Alamofire.HTTPMethod { get } 125 | var params: Parameters? { get } 126 | var encoding: Alamofire.ParameterEncoding { get } 127 | } 128 | 129 | extension AppEndpoint { 130 | func request(withBaseURL baseURL: String) -> DataRequest { 131 | let url = URL(base: baseURL, path: path)! 132 | 133 | let headers: HTTPHeaders = ["APIKEY": "MY API KEY"] 134 | 135 | return Alamofire.request(url, 136 | method: method, 137 | parameters: params, 138 | encoding: encoding, 139 | headers: headers) 140 | } 141 | } 142 | ```` 143 | 144 | Some notes: 145 | 146 | - First we build the URL from the baseURL and the endpoint path. To build the URL we use a Raccoon extension for `URL`. 147 | - Next we add the api key to the headers. 148 | - We build the request using the info provided by the endpoint and return it. 149 | 150 | After we have our protocol, we can create the endpoints. 151 | 152 | ````swift 153 | enum UserEndpoint: AppEndpoint { 154 | case list 155 | case detail(id: Int) 156 | 157 | // MARK: AppEndpoint 158 | var method: Alamofire.HTTPMethod { return .get } 159 | var encoding: Alamofire.ParameterEncoding { return JSONEncoding() } 160 | var params: Parameters? { return nil } 161 | 162 | var path: String { 163 | switch self { 164 | case .list: 165 | return "users" 166 | case let .detail(id): 167 | return "users/\(id)/" 168 | } 169 | } 170 | } 171 | ```` 172 | 173 | Now, we are ready to send the requests. 174 | 175 | ### Enqueueing requests 176 | 177 | Once we have the `Client` and the `Endpoint`, enqueue the request is very easy: 178 | 179 | 180 | ````swift 181 | let client = Client(context: context) 182 | 183 | client.enqueue(UserEndpoint.list) 184 | .then { (users: Many) in 185 | print(users) 186 | } 187 | .catch { error in 188 | print(error) 189 | } 190 | 191 | client.enqueue(UserEndpoint.detail(id: 1)) 192 | .then { (user: User) in 193 | print(user) 194 | } 195 | .catch { error in 196 | print(error) 197 | } 198 | ```` 199 | 200 | #### Cancellable enqueue. 201 | 202 | If you want to cancel a request manually, you can use the `cancellableEnqueue` methods. They return an instance of `Cancellable`, which contains a `Promise` and a `cancel()` method: 203 | 204 | ````swift 205 | let client = Client(context: context) 206 | 207 | let cancellable: Cancellable> = client.cancellableEnqueue(UserEndpoint.list) 208 | 209 | cancellable.promise 210 | .then { (users: Many) in 211 | print(users) 212 | } 213 | .catch { error in 214 | print(error) 215 | } 216 | 217 | 218 | // ... later on 219 | 220 | cancellable.cancel() 221 | 222 | ```` 223 | 224 | ## Advanced usage 225 | 226 | In the previous example, we used Raccoon in its simplest stage. It allows some additional configuration to adapt itself to your REST API design. 227 | 228 | ### Wrapper responses 229 | Let's think we have another call to our api where we perform a login: 230 | 231 | ```` 232 | POST http://sampleapi.com/login/ 233 | ```` 234 | 235 | The response of this requests is this json: 236 | 237 | ````json 238 | { 239 | "token": "authtoken", 240 | "user": {"id": 1, "name": "manue"} 241 | } 242 | ```` 243 | 244 | In this response, we have two parts, one object to be stored "as is" (the token) and a object to be inserted in the context (the user). 245 | 246 | To handle with this, we create a new object that conforms with [AlamofireCoreData Wrapper protocol](https://github.com/ManueGE/AlamofireCoreData#using-wrapper): 247 | 248 | ````swift 249 | struct LoginResponse: Wrapper { 250 | var token: String! 251 | var user: User! 252 | 253 | init() {} 254 | 255 | mutating func map(_ map: Map) { 256 | token <- map["token"] 257 | user <- map["user"] 258 | } 259 | } 260 | ```` 261 | 262 | Now, we can create a new endpoint: 263 | 264 | ````swift 265 | struct LoginEndpoint: RestEndpoint { 266 | let username: String 267 | let password: String 268 | 269 | init(username: String, password: String) { 270 | self.username = username 271 | self.password = password 272 | } 273 | 274 | // MARK: AppEndpoint 275 | var path = "login/" 276 | var method: Alamofire.HTTPMethod = .post 277 | var encoding: Alamofire.ParameterEncoding = JSONEncoding() 278 | var params: Parameters? { 279 | return ["username": username, "password": password] 280 | } 281 | } 282 | ```` 283 | 284 | And then enqueueing it: 285 | 286 | ````swift 287 | let client = Client(context: context) 288 | 289 | client.enqueue(LoginEndpoint(username: "username", password: "password") 290 | .then { (response: LoginResponse) in 291 | print(response.token) // Here you can save your token in the defaults if needed 292 | print(response.user) // User already inserted in the context 293 | } 294 | .catch { error in 295 | print(error) 296 | } 297 | ```` 298 | 299 | ### Custom json serialization 300 | In some cases, the data we get from the server is not in the right format. It could even happens that we have a XML where one of its fields is the JSON we have to parse (yes, I've found things like those 😅). In order to solve this issues, the `Client` protocol has an additional optional var that you can use to transform the response into the JSON you need: 301 | 302 | ````swift 303 | var jsonSerializer: DataResponseSerializer 304 | ```` 305 | 306 | `jsonSerializer ` is just a `Alamofire.DataResponseSerializer`. You can build your serializer as you want; the only condition is that it must return the JSON which you expect and which can be serialized by **Groot**. 307 | 308 | For getting more info about how to build this serializer, please read this section of the [AlamofireCoreData documentation](https://github.com/ManueGE/AlamofireCoreData#transforming-your-json) 309 | 310 | ### Customising the requests 311 | 312 | The `Request` provided by the `Endpoint` can be improved in the client side by using the following `Client` optional method: 313 | 314 | ````swift 315 | func prepare(_ request: DataRequest, for endpoint: Endpoint) -> DataRequest 316 | ```` 317 | 318 | For example, we can add a validator and [a logger for your requests](http://github.com/ManueGE/AlamofireActivityLogger): 319 | 320 | ````swift 321 | func prepare(_ request: DataRequest, for endpoint: Endpoint) -> DataRequest { 322 | return request 323 | .validate() 324 | .log() 325 | } 326 | ```` 327 | 328 | 329 | ### Processing the promise 330 | 331 | Let's suppose we want to save the managed object context every time a request finish successfully. We could add this to every request: 332 | 333 | ````swift 334 | client.enqueue(endpoint) 335 | .then { object: User in 336 | try client.context.save() 337 | } 338 | ```` 339 | 340 | This is not great, you would have to add it to every request. Instead, you can make use of one of the optional methods of the `Client` protocol: 341 | 342 | ````swift 343 | func process(_ promise: Promise, for endpoint: Endpoint) -> Promise 344 | ```` 345 | 346 | This method is called by the client before return the `Promise`. By default it returns the promise itself. 347 | 348 | In our example, you just have to add these lines to your `Client`: 349 | 350 | ````swift 351 | func process(_ promise: Promise, for endpoint: Endpoint) -> Promise { 352 | return promise.then { response -> T in 353 | try self.context.save() 354 | return response 355 | } 356 | } 357 | ```` 358 | 359 | You can do whatever you need with your promise on this method, for example `recover` from some errors or show/hide the network indicator of the status bar. 360 | 361 | - 362 | 363 | ## License 364 | 365 | Raccoon is available under the [MIT license](LICENSE.md). 366 | 367 | ## Contact 368 | [Manuel García-Estañ Martínez](http://github.com/ManueGE) 369 | [@manueGE](https://twitter.com/ManueGE) 370 | -------------------------------------------------------------------------------- /raccoon.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 321A2D621DA868550085E399 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 321A2D611DA868550085E399 /* Endpoint.swift */; }; 11 | 321A2D641DA8689E0085E399 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = 321A2D631DA8689E0085E399 /* Client.swift */; }; 12 | 3285AB891CD019FE00350513 /* Raccoon.h in Headers */ = {isa = PBXBuildFile; fileRef = 3285AB881CD019FE00350513 /* Raccoon.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | 3285AB901CD019FE00350513 /* Raccoon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3285AB861CD019FE00350513 /* Raccoon.framework */; }; 14 | 78B30346D0D4AD1764E3D12B /* Pods_abstract_target_Raccoon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C46CCED049B6F1029FB6131 /* Pods_abstract_target_Raccoon.framework */; }; 15 | E1E8473EF5F1DC4C4E3C1D23 /* Pods_abstract_target_RaccoonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 711C0ADF627C4B11CBD0EDE4 /* Pods_abstract_target_RaccoonTests.framework */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXContainerItemProxy section */ 19 | 3285AB911CD019FE00350513 /* PBXContainerItemProxy */ = { 20 | isa = PBXContainerItemProxy; 21 | containerPortal = 32DDC7761CCFA95A008FC6D5 /* Project object */; 22 | proxyType = 1; 23 | remoteGlobalIDString = 3285AB851CD019FE00350513; 24 | remoteInfo = Raccoon; 25 | }; 26 | /* End PBXContainerItemProxy section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 2C46CCED049B6F1029FB6131 /* Pods_abstract_target_Raccoon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_abstract_target_Raccoon.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | 321A2D611DA868550085E399 /* Endpoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = ""; }; 31 | 321A2D631DA8689E0085E399 /* Client.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = ""; }; 32 | 3285AB861CD019FE00350513 /* Raccoon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Raccoon.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 3285AB881CD019FE00350513 /* Raccoon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Raccoon.h; sourceTree = ""; }; 34 | 3285AB8A1CD019FE00350513 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | 3285AB8F1CD019FE00350513 /* RaccoonTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RaccoonTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | 3285AB961CD019FE00350513 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 37 | 6DEA79D492FB382729AC1680 /* Pods-abstract_target-RaccoonTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-abstract_target-RaccoonTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-abstract_target-RaccoonTests/Pods-abstract_target-RaccoonTests.debug.xcconfig"; sourceTree = ""; }; 38 | 711C0ADF627C4B11CBD0EDE4 /* Pods_abstract_target_RaccoonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_abstract_target_RaccoonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 7F1EB9E06C42FB77CF4402CA /* Pods-abstract_target-Raccoon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-abstract_target-Raccoon.debug.xcconfig"; path = "Pods/Target Support Files/Pods-abstract_target-Raccoon/Pods-abstract_target-Raccoon.debug.xcconfig"; sourceTree = ""; }; 40 | 91B7B199F6351D14F5DBF877 /* Pods-abstract_target-RaccoonTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-abstract_target-RaccoonTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-abstract_target-RaccoonTests/Pods-abstract_target-RaccoonTests.release.xcconfig"; sourceTree = ""; }; 41 | B6EECBC99055AAC5595AD492 /* Pods-abstract_target-Raccoon.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-abstract_target-Raccoon.release.xcconfig"; path = "Pods/Target Support Files/Pods-abstract_target-Raccoon/Pods-abstract_target-Raccoon.release.xcconfig"; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | 3285AB821CD019FE00350513 /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | 78B30346D0D4AD1764E3D12B /* Pods_abstract_target_Raccoon.framework in Frameworks */, 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | 3285AB8C1CD019FE00350513 /* Frameworks */ = { 54 | isa = PBXFrameworksBuildPhase; 55 | buildActionMask = 2147483647; 56 | files = ( 57 | 3285AB901CD019FE00350513 /* Raccoon.framework in Frameworks */, 58 | E1E8473EF5F1DC4C4E3C1D23 /* Pods_abstract_target_RaccoonTests.framework in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 321A2D601DA8635F0085E399 /* source */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 321A2D611DA868550085E399 /* Endpoint.swift */, 69 | 321A2D631DA8689E0085E399 /* Client.swift */, 70 | ); 71 | path = source; 72 | sourceTree = ""; 73 | }; 74 | 3285AB871CD019FE00350513 /* Raccoon */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 3285AB881CD019FE00350513 /* Raccoon.h */, 78 | 3285AB8A1CD019FE00350513 /* Info.plist */, 79 | 321A2D601DA8635F0085E399 /* source */, 80 | ); 81 | path = Raccoon; 82 | sourceTree = ""; 83 | }; 84 | 3285AB931CD019FE00350513 /* RaccoonTests */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 3285AB961CD019FE00350513 /* Info.plist */, 88 | ); 89 | path = RaccoonTests; 90 | sourceTree = ""; 91 | }; 92 | 32DDC7751CCFA95A008FC6D5 = { 93 | isa = PBXGroup; 94 | children = ( 95 | 3285AB871CD019FE00350513 /* Raccoon */, 96 | 3285AB931CD019FE00350513 /* RaccoonTests */, 97 | 32DDC7801CCFA95A008FC6D5 /* Products */, 98 | 3B580E11B197CBE7BBDA8343 /* Pods */, 99 | C6FB965A3F157980BE818A12 /* Frameworks */, 100 | ); 101 | sourceTree = ""; 102 | }; 103 | 32DDC7801CCFA95A008FC6D5 /* Products */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 3285AB861CD019FE00350513 /* Raccoon.framework */, 107 | 3285AB8F1CD019FE00350513 /* RaccoonTests.xctest */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | 3B580E11B197CBE7BBDA8343 /* Pods */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 7F1EB9E06C42FB77CF4402CA /* Pods-abstract_target-Raccoon.debug.xcconfig */, 116 | B6EECBC99055AAC5595AD492 /* Pods-abstract_target-Raccoon.release.xcconfig */, 117 | 6DEA79D492FB382729AC1680 /* Pods-abstract_target-RaccoonTests.debug.xcconfig */, 118 | 91B7B199F6351D14F5DBF877 /* Pods-abstract_target-RaccoonTests.release.xcconfig */, 119 | ); 120 | name = Pods; 121 | sourceTree = ""; 122 | }; 123 | C6FB965A3F157980BE818A12 /* Frameworks */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 2C46CCED049B6F1029FB6131 /* Pods_abstract_target_Raccoon.framework */, 127 | 711C0ADF627C4B11CBD0EDE4 /* Pods_abstract_target_RaccoonTests.framework */, 128 | ); 129 | name = Frameworks; 130 | sourceTree = ""; 131 | }; 132 | /* End PBXGroup section */ 133 | 134 | /* Begin PBXHeadersBuildPhase section */ 135 | 3285AB831CD019FE00350513 /* Headers */ = { 136 | isa = PBXHeadersBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | 3285AB891CD019FE00350513 /* Raccoon.h in Headers */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXHeadersBuildPhase section */ 144 | 145 | /* Begin PBXNativeTarget section */ 146 | 3285AB851CD019FE00350513 /* Raccoon */ = { 147 | isa = PBXNativeTarget; 148 | buildConfigurationList = 3285AB971CD019FE00350513 /* Build configuration list for PBXNativeTarget "Raccoon" */; 149 | buildPhases = ( 150 | 594AFE7DC578B0F927399F1F /* [CP] Check Pods Manifest.lock */, 151 | 3285AB811CD019FE00350513 /* Sources */, 152 | 3285AB821CD019FE00350513 /* Frameworks */, 153 | 3285AB831CD019FE00350513 /* Headers */, 154 | 3285AB841CD019FE00350513 /* Resources */, 155 | ); 156 | buildRules = ( 157 | ); 158 | dependencies = ( 159 | ); 160 | name = Raccoon; 161 | productName = Raccoon; 162 | productReference = 3285AB861CD019FE00350513 /* Raccoon.framework */; 163 | productType = "com.apple.product-type.framework"; 164 | }; 165 | 3285AB8E1CD019FE00350513 /* RaccoonTests */ = { 166 | isa = PBXNativeTarget; 167 | buildConfigurationList = 3285AB9A1CD019FE00350513 /* Build configuration list for PBXNativeTarget "RaccoonTests" */; 168 | buildPhases = ( 169 | 7D7CDA0AF0199FA86C8CF6A2 /* [CP] Check Pods Manifest.lock */, 170 | 3285AB8B1CD019FE00350513 /* Sources */, 171 | 3285AB8C1CD019FE00350513 /* Frameworks */, 172 | 3285AB8D1CD019FE00350513 /* Resources */, 173 | 2FECD4CAB4CA3B34F3F5375C /* [CP] Embed Pods Frameworks */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | 3285AB921CD019FE00350513 /* PBXTargetDependency */, 179 | ); 180 | name = RaccoonTests; 181 | productName = RaccoonTests; 182 | productReference = 3285AB8F1CD019FE00350513 /* RaccoonTests.xctest */; 183 | productType = "com.apple.product-type.bundle.unit-test"; 184 | }; 185 | /* End PBXNativeTarget section */ 186 | 187 | /* Begin PBXProject section */ 188 | 32DDC7761CCFA95A008FC6D5 /* Project object */ = { 189 | isa = PBXProject; 190 | attributes = { 191 | LastSwiftUpdateCheck = 0730; 192 | LastUpgradeCheck = 1000; 193 | ORGANIZATIONNAME = manuege; 194 | TargetAttributes = { 195 | 3285AB851CD019FE00350513 = { 196 | CreatedOnToolsVersion = 7.3; 197 | DevelopmentTeam = CF864KN2XE; 198 | LastSwiftMigration = 1000; 199 | ProvisioningStyle = Automatic; 200 | }; 201 | 3285AB8E1CD019FE00350513 = { 202 | CreatedOnToolsVersion = 7.3; 203 | LastSwiftMigration = 0900; 204 | }; 205 | }; 206 | }; 207 | buildConfigurationList = 32DDC7791CCFA95A008FC6D5 /* Build configuration list for PBXProject "raccoon" */; 208 | compatibilityVersion = "Xcode 3.2"; 209 | developmentRegion = English; 210 | hasScannedForEncodings = 0; 211 | knownRegions = ( 212 | en, 213 | ); 214 | mainGroup = 32DDC7751CCFA95A008FC6D5; 215 | productRefGroup = 32DDC7801CCFA95A008FC6D5 /* Products */; 216 | projectDirPath = ""; 217 | projectRoot = ""; 218 | targets = ( 219 | 3285AB851CD019FE00350513 /* Raccoon */, 220 | 3285AB8E1CD019FE00350513 /* RaccoonTests */, 221 | ); 222 | }; 223 | /* End PBXProject section */ 224 | 225 | /* Begin PBXResourcesBuildPhase section */ 226 | 3285AB841CD019FE00350513 /* Resources */ = { 227 | isa = PBXResourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | 3285AB8D1CD019FE00350513 /* Resources */ = { 234 | isa = PBXResourcesBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | /* End PBXResourcesBuildPhase section */ 241 | 242 | /* Begin PBXShellScriptBuildPhase section */ 243 | 2FECD4CAB4CA3B34F3F5375C /* [CP] Embed Pods Frameworks */ = { 244 | isa = PBXShellScriptBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | ); 248 | inputPaths = ( 249 | "${SRCROOT}/Pods/Target Support Files/Pods-abstract_target-RaccoonTests/Pods-abstract_target-RaccoonTests-frameworks.sh", 250 | "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", 251 | "${BUILT_PRODUCTS_DIR}/AlamofireCoreData/AlamofireCoreData.framework", 252 | "${BUILT_PRODUCTS_DIR}/Groot/Groot.framework", 253 | "${BUILT_PRODUCTS_DIR}/PromiseKit/PromiseKit.framework", 254 | "${BUILT_PRODUCTS_DIR}/OHHTTPStubs/OHHTTPStubs.framework", 255 | ); 256 | name = "[CP] Embed Pods Frameworks"; 257 | outputPaths = ( 258 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", 259 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AlamofireCoreData.framework", 260 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Groot.framework", 261 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/PromiseKit.framework", 262 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OHHTTPStubs.framework", 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | shellPath = /bin/sh; 266 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-abstract_target-RaccoonTests/Pods-abstract_target-RaccoonTests-frameworks.sh\"\n"; 267 | showEnvVarsInLog = 0; 268 | }; 269 | 594AFE7DC578B0F927399F1F /* [CP] Check Pods Manifest.lock */ = { 270 | isa = PBXShellScriptBuildPhase; 271 | buildActionMask = 2147483647; 272 | files = ( 273 | ); 274 | inputPaths = ( 275 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 276 | "${PODS_ROOT}/Manifest.lock", 277 | ); 278 | name = "[CP] Check Pods Manifest.lock"; 279 | outputPaths = ( 280 | "$(DERIVED_FILE_DIR)/Pods-abstract_target-Raccoon-checkManifestLockResult.txt", 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | shellPath = /bin/sh; 284 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 285 | showEnvVarsInLog = 0; 286 | }; 287 | 7D7CDA0AF0199FA86C8CF6A2 /* [CP] Check Pods Manifest.lock */ = { 288 | isa = PBXShellScriptBuildPhase; 289 | buildActionMask = 2147483647; 290 | files = ( 291 | ); 292 | inputPaths = ( 293 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 294 | "${PODS_ROOT}/Manifest.lock", 295 | ); 296 | name = "[CP] Check Pods Manifest.lock"; 297 | outputPaths = ( 298 | "$(DERIVED_FILE_DIR)/Pods-abstract_target-RaccoonTests-checkManifestLockResult.txt", 299 | ); 300 | runOnlyForDeploymentPostprocessing = 0; 301 | shellPath = /bin/sh; 302 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 303 | showEnvVarsInLog = 0; 304 | }; 305 | /* End PBXShellScriptBuildPhase section */ 306 | 307 | /* Begin PBXSourcesBuildPhase section */ 308 | 3285AB811CD019FE00350513 /* Sources */ = { 309 | isa = PBXSourcesBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | 321A2D641DA8689E0085E399 /* Client.swift in Sources */, 313 | 321A2D621DA868550085E399 /* Endpoint.swift in Sources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | 3285AB8B1CD019FE00350513 /* Sources */ = { 318 | isa = PBXSourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | }; 324 | /* End PBXSourcesBuildPhase section */ 325 | 326 | /* Begin PBXTargetDependency section */ 327 | 3285AB921CD019FE00350513 /* PBXTargetDependency */ = { 328 | isa = PBXTargetDependency; 329 | target = 3285AB851CD019FE00350513 /* Raccoon */; 330 | targetProxy = 3285AB911CD019FE00350513 /* PBXContainerItemProxy */; 331 | }; 332 | /* End PBXTargetDependency section */ 333 | 334 | /* Begin XCBuildConfiguration section */ 335 | 3285AB981CD019FE00350513 /* Debug */ = { 336 | isa = XCBuildConfiguration; 337 | baseConfigurationReference = 7F1EB9E06C42FB77CF4402CA /* Pods-abstract_target-Raccoon.debug.xcconfig */; 338 | buildSettings = { 339 | CLANG_ENABLE_MODULES = YES; 340 | CODE_SIGN_IDENTITY = "iPhone Developer"; 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 342 | CODE_SIGN_STYLE = Automatic; 343 | DEFINES_MODULE = YES; 344 | DEVELOPMENT_TEAM = CF864KN2XE; 345 | DYLIB_COMPATIBILITY_VERSION = 1; 346 | DYLIB_CURRENT_VERSION = 1; 347 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 348 | INFOPLIST_FILE = Raccoon/Info.plist; 349 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 350 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 351 | PRODUCT_BUNDLE_IDENTIFIER = com.manuege.Raccoon; 352 | PRODUCT_NAME = "$(TARGET_NAME)"; 353 | PROVISIONING_PROFILE_SPECIFIER = ""; 354 | SKIP_INSTALL = YES; 355 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 356 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 357 | SWIFT_VERSION = 4.2; 358 | }; 359 | name = Debug; 360 | }; 361 | 3285AB991CD019FE00350513 /* Release */ = { 362 | isa = XCBuildConfiguration; 363 | baseConfigurationReference = B6EECBC99055AAC5595AD492 /* Pods-abstract_target-Raccoon.release.xcconfig */; 364 | buildSettings = { 365 | CLANG_ENABLE_MODULES = YES; 366 | CODE_SIGN_IDENTITY = "iPhone Developer"; 367 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 368 | CODE_SIGN_STYLE = Automatic; 369 | DEFINES_MODULE = YES; 370 | DEVELOPMENT_TEAM = CF864KN2XE; 371 | DYLIB_COMPATIBILITY_VERSION = 1; 372 | DYLIB_CURRENT_VERSION = 1; 373 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 374 | INFOPLIST_FILE = Raccoon/Info.plist; 375 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 376 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 377 | PRODUCT_BUNDLE_IDENTIFIER = com.manuege.Raccoon; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | PROVISIONING_PROFILE_SPECIFIER = ""; 380 | SKIP_INSTALL = YES; 381 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 382 | SWIFT_VERSION = 4.2; 383 | }; 384 | name = Release; 385 | }; 386 | 3285AB9B1CD019FE00350513 /* Debug */ = { 387 | isa = XCBuildConfiguration; 388 | baseConfigurationReference = 6DEA79D492FB382729AC1680 /* Pods-abstract_target-RaccoonTests.debug.xcconfig */; 389 | buildSettings = { 390 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 391 | CLANG_ENABLE_MODULES = YES; 392 | INFOPLIST_FILE = RaccoonTests/Info.plist; 393 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 394 | PRODUCT_BUNDLE_IDENTIFIER = com.manuege.RaccoonTests; 395 | PRODUCT_NAME = "$(TARGET_NAME)"; 396 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 397 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 398 | SWIFT_VERSION = 4.0; 399 | }; 400 | name = Debug; 401 | }; 402 | 3285AB9C1CD019FE00350513 /* Release */ = { 403 | isa = XCBuildConfiguration; 404 | baseConfigurationReference = 91B7B199F6351D14F5DBF877 /* Pods-abstract_target-RaccoonTests.release.xcconfig */; 405 | buildSettings = { 406 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)"; 407 | CLANG_ENABLE_MODULES = YES; 408 | INFOPLIST_FILE = RaccoonTests/Info.plist; 409 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 410 | PRODUCT_BUNDLE_IDENTIFIER = com.manuege.RaccoonTests; 411 | PRODUCT_NAME = "$(TARGET_NAME)"; 412 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 413 | SWIFT_VERSION = 4.0; 414 | }; 415 | name = Release; 416 | }; 417 | 32DDC7911CCFA95A008FC6D5 /* Debug */ = { 418 | isa = XCBuildConfiguration; 419 | buildSettings = { 420 | ALWAYS_SEARCH_USER_PATHS = NO; 421 | CLANG_ANALYZER_NONNULL = YES; 422 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 423 | CLANG_CXX_LIBRARY = "libc++"; 424 | CLANG_ENABLE_MODULES = YES; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 427 | CLANG_WARN_BOOL_CONVERSION = YES; 428 | CLANG_WARN_COMMA = YES; 429 | CLANG_WARN_CONSTANT_CONVERSION = YES; 430 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 431 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 432 | CLANG_WARN_EMPTY_BODY = YES; 433 | CLANG_WARN_ENUM_CONVERSION = YES; 434 | CLANG_WARN_INFINITE_RECURSION = YES; 435 | CLANG_WARN_INT_CONVERSION = YES; 436 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 437 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 438 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 439 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 440 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 441 | CLANG_WARN_STRICT_PROTOTYPES = YES; 442 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 443 | CLANG_WARN_UNREACHABLE_CODE = YES; 444 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 445 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 446 | COPY_PHASE_STRIP = NO; 447 | CURRENT_PROJECT_VERSION = 1; 448 | DEBUG_INFORMATION_FORMAT = dwarf; 449 | ENABLE_STRICT_OBJC_MSGSEND = YES; 450 | ENABLE_TESTABILITY = YES; 451 | GCC_C_LANGUAGE_STANDARD = gnu99; 452 | GCC_DYNAMIC_NO_PIC = NO; 453 | GCC_NO_COMMON_BLOCKS = YES; 454 | GCC_OPTIMIZATION_LEVEL = 0; 455 | GCC_PREPROCESSOR_DEFINITIONS = ( 456 | "DEBUG=1", 457 | "$(inherited)", 458 | ); 459 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 460 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 461 | GCC_WARN_UNDECLARED_SELECTOR = YES; 462 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 463 | GCC_WARN_UNUSED_FUNCTION = YES; 464 | GCC_WARN_UNUSED_VARIABLE = YES; 465 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 466 | MTL_ENABLE_DEBUG_INFO = YES; 467 | ONLY_ACTIVE_ARCH = YES; 468 | SDKROOT = iphoneos; 469 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 470 | TARGETED_DEVICE_FAMILY = "1,2"; 471 | VERSIONING_SYSTEM = "apple-generic"; 472 | VERSION_INFO_PREFIX = ""; 473 | }; 474 | name = Debug; 475 | }; 476 | 32DDC7921CCFA95A008FC6D5 /* Release */ = { 477 | isa = XCBuildConfiguration; 478 | buildSettings = { 479 | ALWAYS_SEARCH_USER_PATHS = NO; 480 | CLANG_ANALYZER_NONNULL = YES; 481 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 482 | CLANG_CXX_LIBRARY = "libc++"; 483 | CLANG_ENABLE_MODULES = YES; 484 | CLANG_ENABLE_OBJC_ARC = YES; 485 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 486 | CLANG_WARN_BOOL_CONVERSION = YES; 487 | CLANG_WARN_COMMA = YES; 488 | CLANG_WARN_CONSTANT_CONVERSION = YES; 489 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 490 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 491 | CLANG_WARN_EMPTY_BODY = YES; 492 | CLANG_WARN_ENUM_CONVERSION = YES; 493 | CLANG_WARN_INFINITE_RECURSION = YES; 494 | CLANG_WARN_INT_CONVERSION = YES; 495 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 496 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 497 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 498 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 499 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 500 | CLANG_WARN_STRICT_PROTOTYPES = YES; 501 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 502 | CLANG_WARN_UNREACHABLE_CODE = YES; 503 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 504 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 505 | COPY_PHASE_STRIP = NO; 506 | CURRENT_PROJECT_VERSION = 1; 507 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 508 | ENABLE_NS_ASSERTIONS = NO; 509 | ENABLE_STRICT_OBJC_MSGSEND = YES; 510 | GCC_C_LANGUAGE_STANDARD = gnu99; 511 | GCC_NO_COMMON_BLOCKS = YES; 512 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 513 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 514 | GCC_WARN_UNDECLARED_SELECTOR = YES; 515 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 516 | GCC_WARN_UNUSED_FUNCTION = YES; 517 | GCC_WARN_UNUSED_VARIABLE = YES; 518 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 519 | MTL_ENABLE_DEBUG_INFO = NO; 520 | SDKROOT = iphoneos; 521 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 522 | TARGETED_DEVICE_FAMILY = "1,2"; 523 | VALIDATE_PRODUCT = YES; 524 | VERSIONING_SYSTEM = "apple-generic"; 525 | VERSION_INFO_PREFIX = ""; 526 | }; 527 | name = Release; 528 | }; 529 | /* End XCBuildConfiguration section */ 530 | 531 | /* Begin XCConfigurationList section */ 532 | 3285AB971CD019FE00350513 /* Build configuration list for PBXNativeTarget "Raccoon" */ = { 533 | isa = XCConfigurationList; 534 | buildConfigurations = ( 535 | 3285AB981CD019FE00350513 /* Debug */, 536 | 3285AB991CD019FE00350513 /* Release */, 537 | ); 538 | defaultConfigurationIsVisible = 0; 539 | defaultConfigurationName = Release; 540 | }; 541 | 3285AB9A1CD019FE00350513 /* Build configuration list for PBXNativeTarget "RaccoonTests" */ = { 542 | isa = XCConfigurationList; 543 | buildConfigurations = ( 544 | 3285AB9B1CD019FE00350513 /* Debug */, 545 | 3285AB9C1CD019FE00350513 /* Release */, 546 | ); 547 | defaultConfigurationIsVisible = 0; 548 | defaultConfigurationName = Release; 549 | }; 550 | 32DDC7791CCFA95A008FC6D5 /* Build configuration list for PBXProject "raccoon" */ = { 551 | isa = XCConfigurationList; 552 | buildConfigurations = ( 553 | 32DDC7911CCFA95A008FC6D5 /* Debug */, 554 | 32DDC7921CCFA95A008FC6D5 /* Release */, 555 | ); 556 | defaultConfigurationIsVisible = 0; 557 | defaultConfigurationName = Release; 558 | }; 559 | /* End XCConfigurationList section */ 560 | }; 561 | rootObject = 32DDC7761CCFA95A008FC6D5 /* Project object */; 562 | } 563 | --------------------------------------------------------------------------------