@@ -198,7 +198,7 @@ class APIClient: NSObject {
198198 /// Called when the app is launched by the system by pending tasks
199199 ///
200200 /// - Parameter completionHandler: The completion handler provided by the system and that should be called when the event handling is done.
201- func recreateBackgroundSession( _ completionHandler: ( ( ) -> Void ) ? = nil ) {
201+ func recreateBackgroundSession( _ completionHandler: ( ( ) -> Void ) ? = nil ) {
202202 backgroundSessionCompletionHandler = completionHandler
203203
204204 // Trigger lazy initialisation
@@ -232,9 +232,8 @@ class APIClient: NSObject {
232232 }
233233
234234 // MARK: Generic dataTask handling
235-
236- private func dataTask( context: APIContext , endpoint: String , parameters: [ String : Any ] ? , headers: [ String : String ] ? , method: HTTPMethod , encoding: APIParameterEncoding = . json, completion: @escaping ( AnyObject ? , APIClientError ? ) -> ( ) ) {
237-
235+ private func dataTask( context: APIContext , endpoint: String , parameters: [ String : Any ] ? , headers: [ String : String ] ? , method: HTTPMethod , encoding: APIParameterEncoding = . json, parseJsonResponse: Bool = true , completion: @escaping ( Result < AnyObject , APIClientError > ) -> Void ) {
236+
238237 var request = URLRequest ( url: URL ( string: baseURLString ( for: context) + endpoint) !)
239238
240239 request. httpMethod = method. rawValue
@@ -289,61 +288,72 @@ class APIClient: NSObject {
289288 fatalError ( " API client: Unsupported HTTP method " )
290289 }
291290
292- urlSession. dataTask ( with: request) { ( data, response, error) in
291+ urlSession. dataTask ( with: request) { [ weak welf = self ] ( data, response, error) in
292+ guard let stelf = welf else { return }
293293 guard error == nil else {
294- let error = error as NSError ?
295- switch error!. code {
296- case Int ( CFNetworkErrors . cfurlErrorBadServerResponse. rawValue) :
297- completion ( nil , . server( code: 500 , message: " " ) )
298- case Int ( CFNetworkErrors . cfurlErrorSecureConnectionFailed. rawValue) ..< Int ( CFNetworkErrors . cfurlErrorUnknown. rawValue) :
299- completion ( nil , . connection)
300- default :
301- completion ( nil , . server( code: error!. code, message: error!. localizedDescription) )
302- }
294+ let apiError = stelf. apiClientError ( from: error!)
295+ completion ( . failure( apiError) )
303296 return
304297 }
305-
298+
306299 guard let data = data else {
307- completion ( nil , . parsing( details: " DataTask: Missing data for \( request. url? . absoluteString ?? " " ) " ) )
300+ completion ( . failure ( . parsing( details: " DataTask: Missing data for \( request. url? . absoluteString ?? " " ) " ) ) )
308301 return
309302 }
310303
304+ if !parseJsonResponse {
305+ completion ( . success( data as AnyObject ) )
306+ return
307+ }
308+
311309 // Attempt parsing to JSON
312310 if let json = try ? JSONSerialization . jsonObject ( with: data, options: [ ] ) {
313311 // Check if there's an error in the response
314312 if let responseDictionary = json as? [ String : AnyObject ] ,
315313 let errorDict = responseDictionary [ " error " ] as? [ String : AnyObject ] ,
316314 let errorMessage = ( errorDict [ " message " ] as? [ AnyObject ] ) ? . last as? String {
317- completion ( nil , . server( code: ( response as? HTTPURLResponse ) ? . statusCode ?? 0 , message: errorMessage) )
315+ completion ( . failure ( . server( code: ( response as? HTTPURLResponse ) ? . statusCode ?? 0 , message: errorMessage) ) )
318316 } else {
319- completion ( json as AnyObject , nil )
317+ completion ( . success ( json as AnyObject ) )
320318 }
321- } else if let image = UIImage ( data: data) { // Attempt parsing UIImage
322- completion ( image, nil )
323319 } else { // Parsing error
324320 var details = " DataTask: Bad data for \( request. url? . absoluteString ?? " " ) "
325321 if let stringData = String ( data: data, encoding: String . Encoding. utf8) {
326322 details = details + " : " + stringData
327323 }
328- completion ( nil , . parsing( details: details) )
324+ completion ( . failure ( . parsing( details: details) ) )
329325 }
330326 } . resume ( )
331327 }
328+
329+ private func apiClientError( from error: Error ? ) -> APIClientError {
330+ guard let error = error as NSError ? else { return . generic }
331+
332+ switch error. code {
333+ case Int ( CFNetworkErrors . cfurlErrorBadServerResponse. rawValue) :
334+ return . server( code: 500 , message: " " )
335+ case Int ( CFNetworkErrors . cfurlErrorSecureConnectionFailed. rawValue) ..< Int ( CFNetworkErrors . cfurlErrorUnknown. rawValue) :
336+ return . connection
337+ default :
338+ return . server( code: error. code, message: error. localizedDescription)
339+ }
340+ }
341+
332342
333343 // MARK: - Public methods
334- func post( context: APIContext , endpoint: String , parameters: [ String : Any ] ? = nil , headers: [ String : String ] ? = nil , encoding: APIParameterEncoding = . json, completion: @escaping ( AnyObject ? , APIClientError ? ) -> ( ) ) {
335- dataTask ( context: context, endpoint: endpoint, parameters: parameters, headers: headers, method: . post, encoding: encoding, completion: completion)
344+ func post( context: APIContext , endpoint: String , parameters: [ String : Any ] ? = nil , headers: [ String : String ] ? = nil , encoding: APIParameterEncoding = . json, parseJsonResponse : Bool = true , completion: @escaping ( Result < AnyObject , APIClientError > ) -> Void ) {
345+ dataTask ( context: context, endpoint: endpoint, parameters: parameters, headers: headers, method: . post, encoding: encoding, parseJsonResponse : parseJsonResponse , completion: completion)
336346 }
337347
338- func get( context: APIContext , endpoint: String , parameters: [ String : Any ] ? = nil , headers: [ String : String ] ? = nil , completion: @escaping ( AnyObject ? , APIClientError ? ) -> ( ) ) {
339- dataTask ( context: context, endpoint: endpoint, parameters: parameters, headers: headers, method: . get, completion: completion)
348+ func get( context: APIContext , endpoint: String , parameters: [ String : Any ] ? = nil , headers: [ String : String ] ? = nil , parseJsonResponse : Bool = true , completion: @escaping ( Result < AnyObject , APIClientError > ) -> Void ) {
349+ dataTask ( context: context, endpoint: endpoint, parameters: parameters, headers: headers, method: . get, parseJsonResponse : parseJsonResponse , completion: completion)
340350 }
341351
342- func put( context: APIContext , endpoint: String , parameters: [ String : Any ] ? = nil , headers: [ String : String ] ? = nil , completion: @escaping ( AnyObject ? , APIClientError ? ) -> ( ) ) {
352+ func put( context: APIContext , endpoint: String , parameters: [ String : Any ] ? = nil , headers: [ String : String ] ? = nil , completion: @escaping ( Result < AnyObject , APIClientError > ) -> Void ) {
343353 dataTask ( context: context, endpoint: endpoint, parameters: parameters, headers: headers, method: . put, completion: completion)
344354 }
345355
346- func uploadImage( _ data: Data , imageName: String , completion: @escaping ( AnyObject ? , Error ? ) -> ( ) ) {
356+ func uploadImage( _ data: Data , imageName: String , completion: @escaping ( Result < AnyObject , APIClientError > ) -> Void ) {
347357 let boundaryString = " Boundary- \( NSUUID ( ) . uuidString) "
348358 let fileUrl = createFileWith ( imageData: data, imageName: imageName, boundaryString: boundaryString)
349359
@@ -353,28 +363,27 @@ class APIClient: NSObject {
353363 request. setValue ( " application/json " , forHTTPHeaderField: " Accept " )
354364 request. setValue ( " multipart/form-data; boundary= \( boundaryString) " , forHTTPHeaderField: " content-type " )
355365
356- URLSession . shared. uploadTask ( with: request, fromFile: fileUrl) { ( data, response, error) in
366+ URLSession . shared. uploadTask ( with: request, fromFile: fileUrl) { [ weak welf = self ] ( data, response, error) in
367+ guard let stelf = welf else { return }
357368 guard let data = data, let json = try ? JSONSerialization . jsonObject ( with: data, options: [ ] ) else {
358- DispatchQueue . main. async { completion ( nil , error) }
369+ let error = stelf. apiClientError ( from: error)
370+ DispatchQueue . main. async { completion ( . failure( error) ) }
359371 return
360372 }
361373
362- DispatchQueue . main. async { completion ( json as AnyObject , nil ) }
363-
374+ DispatchQueue . main. async { completion ( . success( json as AnyObject ) ) }
364375 } . resume ( )
365376 }
366377
367- func uploadImage( _ image: UIImage , imageName: String , completion: @escaping ( AnyObject ? , Error ? ) -> ( ) ) {
368-
378+ func uploadImage( _ image: UIImage , imageName: String , completion: @escaping ( Result < AnyObject , APIClientError > ) -> Void ) {
369379 guard let imageData = imageData ( withImage: image, imageName: imageName) else {
370380 print ( " Image Upload: cannot read image data " )
371- completion ( nil , nil )
381+ completion ( . failure ( APIClientError . generic ) )
372382 return
373383 }
374-
375384 uploadImage ( imageData, imageName: imageName, completion: completion)
376385 }
377-
386+
378387 func uploadImage( _ data: Data , imageName: String , reference: String ? ) {
379388 let boundaryString = " Boundary- \( NSUUID ( ) . uuidString) "
380389 let fileUrl = createFileWith ( imageData: data, imageName: imageName, boundaryString: boundaryString)
@@ -422,14 +431,22 @@ class APIClient: NSObject {
422431 uploadImage ( fileData, imageName: imageName, reference: reference)
423432 }
424433
425- func downloadImage( _ imageUrl: URL , completion: @escaping ( ( UIImage ? , Error ? ) -> Void ) ) {
426- SDWebImageManager . shared ( ) . loadImage ( with: imageUrl, options: [ ] , progress: nil , completed: { image, _, error, _, _, _ in
434+ func downloadImage( _ imageUrl: URL , completion: @escaping ( ( Result < UIImage , APIClientError > ) -> Void ) ) {
435+ SDWebImageManager . shared ( ) . loadImage ( with: imageUrl, options: [ ] , progress: nil , completed: { [ weak welf = self ] image, _, error, _, _, _ in
436+ guard let stelf = welf else { return }
427437 DispatchQueue . main. async {
428- completion ( image, error)
438+ if let image = image, error == nil {
439+ completion ( . success( image) )
440+ } else if let error = error {
441+ let error = stelf. apiClientError ( from: error)
442+ completion ( . failure( error) )
443+ } else {
444+ completion ( . failure( APIClientError . generic) )
445+ }
429446 }
430447 } )
431448 }
432-
449+
433450 func uploadPdf( _ file: URL , to targetUrl: URL , reference: String ? ) {
434451 guard let _ = try ? Data ( contentsOf: file) else {
435452 print ( " File Upload: cannot read file data " )
@@ -456,7 +473,7 @@ class APIClient: NSObject {
456473 dataTask. resume ( )
457474 }
458475
459- func pendingBackgroundTaskCount( _ completion: @escaping ( ( Int ) -> Void ) ) {
476+ func pendingBackgroundTaskCount( _ completion: @escaping ( ( Int ) -> Void ) ) {
460477 backgroundUrlSession. getAllTasks { completion ( $0. count) }
461478 }
462479
@@ -469,7 +486,7 @@ class APIClient: NSObject {
469486 }
470487 }
471488
472- func updateTaskReferences( completion: @escaping ( ) -> ( ) ) {
489+ func updateTaskReferences( completion: @escaping ( ) -> Void ) {
473490 backgroundUrlSession. getAllTasks { [ weak welf = self ] ( tasks) in
474491 guard let stelf = welf else { return }
475492 stelf. taskReferences = stelf. taskReferences. filter ( { ( key, _) -> Bool in
0 commit comments