使用 Moya/RxSwift 进行网络请求
Moya 其实就是一个对 Alamofire 的更高层的封装。
Alamofire 进行网络请求:
1
2
3
4
5
6
7
8
9
10func GETRequest(URLString: URLStringConvertible, NetData: (data: NSData?)->Void) {
Alamofire.request(.GET, URLString).responseJSON {
response in
switch response.result {
case .Success:
NetData(data: response.data)
case .Failure( _):
}
}
}
Moya 进行网络请求:
1
2
3
4
5
6
7
8
9
10
11func requestDataWithTarget<T: Decodable>(target: ArtsyAPI, type: T.Type, successClosure: [T] -> Void, failClosure: ORMError -> Void) {
RxMoyaProvider<ArtsyAPI>().request(target).mapSuccessfulHTTPToObject(T).subscribe(
onNext: { item in
successClosure(item)
},
onError: { error in
if let error = error as? ORMError {
failClosure(error)
}
}).addDisposableTo(DisposeBag())
}
可见 Moya 将url
、method
、parameters
、json解析
等都隐藏起来,封装到其他地方了。当然,我选择 Moya 最主要的理由其实是 Moya 本身提供了 RxSwift 扩展,可以无缝衔接 RxSwift 和 ReactiveCocoa。这里我借鉴了 Emergence 在网络请求方面的方法,这对于响应式编程和 MVVM 架构的学习还是还是很有帮助的。
使用 Moya 的第一步就是定义一个 Target,Target 本身其实就是一个符合 TargetType protocol 的集合。
1
2
3
4
5
6
7
8
9public enum WeatherAPI: TargetType {
case loadWeatherInfo()
public var baseURL: NSURL { return NSURL(string: "http://weather.123.duba.net")! }
public var path: String { return "/static/weather_info/101110101.html" }
public var method: Moya.Method { return .GET }
public var parameters: [String: AnyObject]? { return nil }
public var sampleData: NSData { return NSData() }
}
其中 sampleData 是单元测试用的,所以 Moya 的另外一个优点是单元测试很方便。
而 json 解析方面,Emergence 中的方法已经很好了,可以直接拿来用。数据的初步解析和判断可以根据具体情况适当修改。
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
56enum ORMError : ErrorType {
case ORMNoRepresentor
case ORMNotSuccessfulHTTP
case ORMNoData
case ORMCouldNotMakeObjectError
}
extension Observable {
func mapSuccessfulHTTPToObject<T: Decodable>(type: T.Type) -> Observable<[T]> {
func resultFromJSON(object:[String: AnyObject], classType: T.Type) -> T? {
return classType.init(json: object)
}
return map { representor in
guard let response = representor as? Response else {
throw ORMError.ORMNoRepresentor
}
guard ((200...209) ~= response.statusCode) else {
if let json = try? NSJSONSerialization.JSONObjectWithData(response.data, options: .AllowFragments) as? [String: AnyObject] {
print("Got error message: \(json)")
}
throw ORMError.ORMNotSuccessfulHTTP
}
do {
guard let json = try NSJSONSerialization.JSONObjectWithData(response.data, options: .AllowFragments) as? [String: AnyObject] else {
throw ORMError.ORMCouldNotMakeObjectError
}
if let status = json["status"] as? String {
if status == "100" {
if let result = json["result"] as? [String: AnyObject] {
if let array = result["array"] as? [[String : AnyObject]] {
var objects = [T]()
for dict in array {
if let obj = resultFromJSON(dict, classType:type) {
objects.append(obj)
}
}
return objects
}else {
return [resultFromJSON(result, classType:type)!]
}
}else {
throw ORMError.ORMNoData
}
}else if status == "200" {
throw ORMError.ORMNoRepresentor
}else if status == "300" {
throw ORMError.ORMNoData
}else {
throw ORMError.ORMCouldNotMakeObjectError
}
}else {
throw ORMError.ORMCouldNotMakeObjectError
}
}
}
}
}
当然,这还需要一个 json 解析转换库搭配,swift 的相关第三方开源库很多,通过 Moya+RxSwift+Argo 完成网络请求 用的是 Argo,Emergence 用的是 Gloss,这个看个人喜好,我选的是 Gloss。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import UIKit
import Gloss
struct WeatherInfo {
let cityName: String?
let weather: String?
let temp: String?
let date: String?
}
extension WeatherInfo: Decodable {
init?(json: JSON) {
self.cityName = "city" <~~ json
self.weather = "weather1" <~~ json
self.temp = "temp1" <~~ json
self.date = "date_y" <~~ json
}
}
最后,网络请求就很简单了。
1
2
3
4
5TENetDataManager.sharedNetDataManager.requestDataWithTarget(ArtsyAPI.executeEmpLogin(empAccount: userNameStr, empPassword: passwordStr), type: UserInfo.self, successClosure: { (result) in
}) { (error) in
}