forked from Haneke/HanekeSwift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
NetworkFetcher.swift
105 lines (77 loc) · 3.6 KB
/
NetworkFetcher.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//
// NetworkFetcher.swift
// Haneke
//
// Created by Hermes Pique on 9/12/14.
// Copyright (c) 2014 Haneke. All rights reserved.
//
import UIKit
extension HanekeGlobals {
// It'd be better to define this in the NetworkFetcher class but Swift doesn't allow to declare an enum in a generic type
public struct NetworkFetcher {
public enum ErrorCode : Int {
case InvalidData = -400
case MissingData = -401
case InvalidStatusCode = -402
}
}
}
public class NetworkFetcher<T : DataConvertible> : Fetcher<T> {
let URL : NSURL
public init(URL : NSURL) {
self.URL = URL
let key = URL.absoluteString
super.init(key: key)
}
public var session : NSURLSession { return NSURLSession.sharedSession() }
var task : NSURLSessionDataTask? = nil
var cancelled = false
// MARK: Fetcher
public override func fetch(failure fail : ((NSError?) -> ()), success succeed : (T.Result) -> ()) {
self.cancelled = false
self.task = self.session.dataTaskWithURL(self.URL) {[weak self] (data, response, error) -> Void in
if let strongSelf = self {
strongSelf.onReceiveData(data, response: response, error: error, failure: fail, success: succeed)
}
}
self.task?.resume()
}
public override func cancelFetch() {
self.task?.cancel()
self.cancelled = true
}
// MARK: Private
private func onReceiveData(data: NSData!, response: NSURLResponse!, error: NSError!, failure fail: ((NSError?) -> ()), success succeed: (T.Result) -> ()) {
if cancelled { return }
let URL = self.URL
if let error = error {
if (error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled) { return }
Log.debug("Request \(URL.absoluteString) failed", error)
dispatch_async(dispatch_get_main_queue(), { fail(error) })
return
}
if let httpResponse = response as? NSHTTPURLResponse where !httpResponse.hnk_isValidStatusCode() {
let description = NSHTTPURLResponse.localizedStringForStatusCode(httpResponse.statusCode)
self.failWithCode(.InvalidStatusCode, localizedDescription: description, failure: fail)
return
}
if !response.hnk_validateLengthOfData(data) {
let localizedFormat = NSLocalizedString("Request expected %ld bytes and received %ld bytes", comment: "Error description")
let description = String(format:localizedFormat, response.expectedContentLength, data.length)
self.failWithCode(.MissingData, localizedDescription: description, failure: fail)
return
}
guard let value = T.convertFromData(data) else {
let localizedFormat = NSLocalizedString("Failed to convert value from data at URL %@", comment: "Error description")
let description = String(format:localizedFormat, URL.absoluteString)
self.failWithCode(.InvalidData, localizedDescription: description, failure: fail)
return
}
dispatch_async(dispatch_get_main_queue()) { succeed(value) }
}
private func failWithCode(code: HanekeGlobals.NetworkFetcher.ErrorCode, localizedDescription: String, failure fail: ((NSError?) -> ())) {
let error = errorWithCode(code.rawValue, description: localizedDescription)
Log.debug(localizedDescription, error)
dispatch_async(dispatch_get_main_queue()) { fail(error) }
}
}