@@ -56,10 +56,13 @@ private extension NSURLSessionDataTask {
56
56
}
57
57
58
58
// use private, global scope variable until we can use stored class var in Swift 1.2
59
- private var instancePairDictionary = [ String: ( API, NSURLSession) ] ( )
60
- private let instancePairSemaphore = dispatch_semaphore_create ( 1 )
59
+ private let internalDefaultURLSession = NSURLSession (
60
+ configuration: NSURLSessionConfiguration . defaultSessionConfiguration ( ) ,
61
+ delegate: URLSessionDelegate ( ) ,
62
+ delegateQueue: nil
63
+ )
61
64
62
- public class API : NSObject , NSURLSessionDelegate , NSURLSessionDataDelegate {
65
+ public class API {
63
66
// configurations
64
67
public class func baseURL( ) -> NSURL {
65
68
fatalError ( " API.baseURL() must be overrided in subclasses. " )
@@ -72,47 +75,13 @@ public class API: NSObject, NSURLSessionDelegate, NSURLSessionDataDelegate {
72
75
public class func responseBodyParser( ) -> ResponseBodyParser {
73
76
return . JSON( readingOptions: nil )
74
77
}
75
-
76
- public class func URLSessionConfiguration( ) -> NSURLSessionConfiguration {
77
- return NSURLSessionConfiguration . defaultSessionConfiguration ( )
78
- }
79
-
80
- public class func URLSessionDelegateQueue( ) -> NSOperationQueue ? {
81
- // nil indicates NSURLSession creates its own serial operation queue.
82
- // see doc of NSURLSession.init(configuration:delegate:delegateQueue:) for more details.
83
- return nil
84
- }
85
-
86
- // prevent instantiation
87
- override private init ( ) {
88
- super. init ( )
89
- }
90
-
91
- // create session and instance of API for each subclasses
92
- private final class var instancePair : ( API , NSURLSession ) {
93
- let className = NSStringFromClass ( self )
94
-
95
- dispatch_semaphore_wait ( instancePairSemaphore, DISPATCH_TIME_FOREVER)
96
- let pair : ( API , NSURLSession ) = instancePairDictionary [ className] ?? {
97
- let instance = ( self as NSObject . Type) ( ) as API
98
- let configuration = self . URLSessionConfiguration ( )
99
- let queue = self . URLSessionDelegateQueue ( )
100
- let session = NSURLSession ( configuration: configuration, delegate: instance, delegateQueue: queue)
101
- let pair = ( instance, session)
102
- instancePairDictionary [ className] = pair
103
- return pair
104
- } ( )
105
- dispatch_semaphore_signal ( instancePairSemaphore)
106
-
107
- return pair
108
- }
109
-
110
- public final class var instance : API {
111
- return instancePair. 0
78
+
79
+ public class var defaultURLSession : NSURLSession {
80
+ return internalDefaultURLSession
112
81
}
113
-
114
- public final class var URLSession : NSURLSession {
115
- return instancePair . 1
82
+
83
+ public class var acceptableStatusCodes : [ Int ] {
84
+ return [ Int ] ( 200 ..< 300 )
116
85
}
117
86
118
87
// build NSURLRequest
@@ -146,13 +115,22 @@ public class API: NSObject, NSURLSessionDelegate, NSURLSessionDataDelegate {
146
115
}
147
116
}
148
117
149
- // send request and build response object
118
+ // In Swift 1.1, we could not omit `URLSession` argument of `func send(request:URLSession(=default):handler(=default):)`
119
+ // with trailing closure, so we provide following 2 methods
120
+ // - `func sendRequest(request:handler(=default):)`
121
+ // - `func sendRequest(request:URLSession:handler(=default):)`.
122
+ // In Swift 1.2, we can omit default arguments with trailing closure, so they should be replaced with
123
+ // - `func sendRequest(request:URLSession(=default):handler(=default):)`
150
124
public class func sendRequest< T: Request > ( request: T , handler: ( Result < T . Response , NSError > ) -> Void = { r in } ) -> NSURLSessionDataTask ? {
151
- let session = URLSession
125
+ return sendRequest ( request, URLSession: defaultURLSession, handler: handler)
126
+ }
127
+
128
+ // send request and build response object
129
+ public class func sendRequest< T: Request > ( request: T , URLSession: NSURLSession , handler: ( Result < T . Response , NSError > ) -> Void = { r in } ) -> NSURLSessionDataTask ? {
152
130
let mainQueue = dispatch_get_main_queue ( )
153
131
154
132
if let URLRequest = request. URLRequest {
155
- let task = session . dataTaskWithRequest ( URLRequest)
133
+ let task = URLSession . dataTaskWithRequest ( URLRequest)
156
134
157
135
task. completionHandler = { data, URLResponse, connectionError in
158
136
if let error = connectionError {
@@ -161,10 +139,15 @@ public class API: NSObject, NSURLSessionDelegate, NSURLSessionDataDelegate {
161
139
}
162
140
163
141
let statusCode = ( URLResponse as? NSHTTPURLResponse ) ? . statusCode ?? 0
164
- if !contains( 200 ..< 300 , statusCode) {
165
- let userInfo = [ NSLocalizedDescriptionKey: " received status code that represents error " ]
166
- let error = NSError ( domain: APIKitErrorDomain, code: statusCode, userInfo: userInfo)
167
- dispatch_async ( mainQueue, { handler ( . Failure( Box ( error) ) ) } )
142
+ if !contains( self . acceptableStatusCodes, statusCode) {
143
+ let error : NSError = {
144
+ switch self . responseBodyParser ( ) . parseData ( data) {
145
+ case . Success( let box) : return self . responseErrorFromObject ( box. unbox)
146
+ case . Failure( let box) : return box. unbox
147
+ }
148
+ } ( )
149
+
150
+ dispatch_async ( mainQueue) { handler ( failure ( error) ) }
168
151
return
169
152
}
170
153
@@ -176,8 +159,8 @@ public class API: NSObject, NSURLSessionDelegate, NSURLSessionDataDelegate {
176
159
let error = NSError ( domain: APIKitErrorDomain, code: 0 , userInfo: userInfo)
177
160
return failure ( error)
178
161
}
179
-
180
162
}
163
+
181
164
dispatch_async ( mainQueue, { handler ( mappedResponse) } )
182
165
}
183
166
@@ -193,17 +176,23 @@ public class API: NSObject, NSURLSessionDelegate, NSURLSessionDataDelegate {
193
176
}
194
177
}
195
178
179
+ public class func responseErrorFromObject( object: AnyObject ) -> NSError {
180
+ let userInfo = [ NSLocalizedDescriptionKey: " received status code that represents error " ]
181
+ let error = NSError ( domain: APIKitErrorDomain, code: 0 , userInfo: userInfo)
182
+ return error
183
+ }
184
+ }
185
+
186
+ public class URLSessionDelegate : NSObject , NSURLSessionDelegate , NSURLSessionDataDelegate {
196
187
// MARK: - NSURLSessionTaskDelegate
197
- // TODO: add attributes like NS_REQUIRES_SUPER when it is available in future version of Swift.
198
188
public func URLSession( session: NSURLSession , task: NSURLSessionTask , didCompleteWithError connectionError: NSError ? ) {
199
189
if let dataTask = task as? NSURLSessionDataTask {
200
190
dataTask. completionHandler ? ( dataTask. responseBuffer, dataTask. response, connectionError)
201
191
}
202
192
}
203
193
204
194
// MARK: - NSURLSessionDataDelegate
205
- // TODO: add attributes like NS_REQUIRES_SUPER when it is available in future version of Swift.
206
195
public func URLSession( session: NSURLSession , dataTask: NSURLSessionDataTask , didReceiveData data: NSData ) {
207
196
dataTask. responseBuffer. appendData ( data)
208
- }
197
+ }
209
198
}
0 commit comments