我们平常的网络请求基本步骤
1 发送Request
2 接受 Response
3 json
转model
(我目前是有这一步的)
1 不利用三方框架的Rx网络层
在实际生产过程中,我们都会使用第三方的网络框架。但为了学习基本流程,我们最好还是实现自己的一套简易框架。
1.1 对URLSession
进行Rx扩展,让他用它Rx的功能
创建URLSession+Rx
文件
func response(request: URLRequest) -> Observable<(HTTPURLResponse, Data)> {
return Observable.create { observable in
let task = self.base.dataTask(with: request) { (data, response, error) in
//处理数据
if let error = error {
observable.onError(error)
return
}
observable.onNext((response as! HTTPURLResponse, data!))
observable.onCompleted()
}
task.resume()
return Disposables.create(with: task.cancel)
}
}
我们拆分来看一下
func response(request: URLRequest) -> Observable<(HTTPURLResponse, Data)> {
return Observable.create { observable in
//请求
return Disposables.create()
}
}
这几乎是rx扩展的基本样式,中间加上URLSesson
的请求 和 请求之后发送 错误 或者完成信号就可以了。
我们来看一下成果
let request = URLRequest.init(url: URL.init(string: "")!)
let response = URLSession.shared.rx.response(request: request)
response.subscribe(onNext: { (response, data) in
//数据处理
}).addDisposableTo(bag)
数据处理这部分也挺恶心了,也应该封装起来
通常数据处理 我们先处理data -> json ,之后json ->model. 事实上 不是所有的VC需要的数据都是model.所以 我们要暴露json 和model 2个接口。供调用者选用
在处理数据之前要确定数据是否有效,根据返回的状态码来判断,
筛选出正常返回的数据
func data(request: URLRequest) -> Observable<Data> {
return response(request: request).map { (response, data) in
if 200..<300 ~= response.statusCode {
return data
} else {
throw URLSessionError.failed
}
}
}
json
func json(request: URLRequest) -> Observable<[String: Any]> {
return data(request: request).map{ data in
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]
return json!
}
}
model
转化model 这一步 这里我没有自己用原生实现,Swift不支持运行时(不包含继承NSObject的类)这里偷偷的用一下三方吧ObjectMapper
(用法 后面介绍)
func model<T: Mappable>(request: URLRequest, model: T.Type) -> Observable<T> {
return json(request: request).map{ json in
let object = Mapper<T>().map(JSONObject: json["data"])
return object!
}
}
这里的转model 在实际情况下会出现许多问题。举个例子
商品列表 商品详情
商品详情是单纯的model
商品列表是 model的数组,所以根据不同情况可能还需要一个ModelArray的方法。和model的一样,就不在重复了。
我们到VM中看看我们的战果
let request = URLRequest.init(url: URL.init(string: "")!)
let response = URLSession.shared.rx.model(request: request, model: GoodsDetailModel.self)
response.subscribe(onNext: { model in
//数据处理
}).addDisposableTo(bag)
这样我们一个基本的rx 的网络层基本完成了。如果要使用可以放在一个NetWorkingService类 。避免于vm大量的耦合。具体封装方法 就看大家的想法啦。是集约型 还是 分散型,都看自己的喜好了
2 RxMoya
在生产中,强烈推荐RxMoya真的大而全。
这边我们简单的介绍使用方法
首先确定配置文件创建XXAPI.Swift
我随便写一个了
enum GoodsAPI {
case goodsDetail(goodsID: String)
}
extension GoodsAPI: TargetType {
var parameterEncoding: ParameterEncoding {
return URLEncoding.default
}
var task: Task {
return .request
}
var path: String {
return ""
}
var base: String {
return ""
}
var baseURL: URL {
return URL.init(string: base)!
}
var parameters: [String: Any]? {
switch self {
case .goodsDetail(let id):
return []
default:
return nil
}
}
var method: Moya.Method {
return .post
}
var sampleData: Data {
return "".data(using: .utf8)!
}
}
遵循TargetType
实现基本配置
然后在VM中调用
let service = RxMoyaProvider<GoodsAPI>()
var goodsDetailModel: Observable<GoodsDetailModel> {
return self.service.request(.goodsDetail(goodsID: "10133")).mapObject(GoodsDetailModel.self)
}
这样就可以让VM中的model暴露给VC使用了。简单方便
=========
介绍下ObjectMapper的使用
1 遵循 Mappable协议
2 实现协议方法 init 和 mapping
这里的mapping 一定要写映射关系,毕竟没有运行时这种东西了。
注意的是如果返回的Int类型,你用String 是无法接受的(很难受)
struct GoodsDetailModel: Mappable {
var goodsID: Int?
var goodsInfo: String?
var goodsName: String?
var introduction: String?
var label: String?
var tag: String?
var goodsPic: String?
var xPrice: String?
var yPrice: String?
var number: Int?
var batchNO: String?
var activityGoods: Bool?
init?(map: Map) {
}
mutating func mapping(map: Map) {
goodsID <- map["goodsID"]
goodsInfo <- map["goodsInfo"]
goodsName <- map["goodsName"]
introduction <- map["introduction"]
label <- map["label"]
tag <- map["tag"]
goodsPic <- map["goodsPic"]
xPrice <- map["xPrice"]
yPrice <- map["yPrice"]
number <- map["number"]
batchNO <- map["batchNO"]
activityGoods <- map["activityGoods"]
}
}
网友评论