前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >moya + RxSwift 进行网络请求

moya + RxSwift 进行网络请求

作者头像
全栈程序员站长
发布2022-11-17 16:33:13
1.8K0
发布2022-11-17 16:33:13
举报

1.关于moya

如在OC中使用AFNetworking一般,Swift我们用Alamofire来做网络库.而Moya在Alamofire的基础上又封装了一层:

moya
moya

官方说moya有以下特性(我也就信了):

  • 编译时检查正确的API端点访问.
  • 使你定义不同端点枚举值对应相应的用途更加明晰.
  • 提高测试地位从而使单元测试更加容易.

2.开始

1.创建枚举API

就像这样:

enum APIManager {
    case getNewsLatest//获取最新消息
    case getStartImage// 启动界面图像获取
    case getVersion(String)//软件版本查询
    case getThemes//主题日报列表查看
    case getNewsDetail(Int)//获取新闻详情
}

Jetbrains全家桶1年46,售后保障稳定

2.实现TargetType协议

就像这样:

extension APIManager: TargetType {
/// The target's base `URL`.
var baseURL: URL {
return URL.init(string: "http://news-at.zhihu.com/api/")!
}
/// The path to be appended to `baseURL` to form the full `URL`.
var path: String {
switch self {
case .getNewsLatest:
return "4/news/latest"
case .getStartImage://start-image 后为图像分辨率,接受任意的 number*number 格式, number 为任意非负整数,返回值均相同。
return "4/start-image/1080*1776"
case .getVersion(let version)://URL 最后部分的数字代表所安装『知乎日报』的版本
return "4/version/ios/" + version
case .getThemes:
return "4/themes"
case .getNewsDetail(let id):
return "4/news/\(id)"
}
}
/// The HTTP method used in the request.
var method: Moya.Method {
return .get
}
/// The parameters to be incoded in the request.
var parameters: [String: Any]? {
return nil
}
/// The method used for parameter encoding.
var parameterEncoding: ParameterEncoding {
return URLEncoding.default
}
/// Provides stub data for use in testing.
var sampleData: Data {
return "".data(using: String.Encoding.utf8)!
}
/// The type of HTTP task to be performed.
var task: Task {
return .request
}
/// Whether or not to perform Alamofire validation. Defaults to `false`.
var validate: Bool {
return false
}
}

在这里,可以设置请求的参数,例如url……method……para等.

3.使用

Moya的使用非常简单,通过TargetType协议定义好每个target之后,就可以直接使用Moya开始发送网络请求了。就像这样:

let provider = MoyaProvider<APIManager>()
provider.request(.getNewsLatest) { result in
// do something with result
}

3.配合RxSwift

Moya本身已经是一个使用起来非常方便,能够写出非常简洁优雅的代码的网络封装库,但是让Moya变得更加强大的原因之一还因为它对于Functional Reactive Programming的扩展,具体说就是对于RxSwiftReactiveCocoa的扩展,通过与这两个库的结合,能让Moya变得更加强大。我选择RxSwift的原因有两个,一个是RxSwift的库相对来说比较轻量级,语法更新相对来说比较少,我之前用过ReactiveCocoa,一些大版本的更新需求重写很多代码,第二个更重要的原因是因为RxSwift背后有整个ReactiveX的支持,里面包括JavaJS.Net, SwiftScala,它们内部都用了ReactiveX的逻辑思想,这意味着你一旦学会了其中的一个,以后可以很快的上手ReactiveX中的其他语言。

Moya提供了非常方面的RxSwift扩展:

let provider = RxMoyaProvider<APIManager>()
provider.request(.getNewsLatest)
.filterSuccessfulStatusCodes()
.mapJSON()
.subscribe(onNext: { (json) in
//do something with posts
print(json)
})
.addDisposableTo(disposeBag)

解释一下:

  • RxMoyaProviderMoyaProvider的子类,是对RxSwift的扩展
  • filterSuccessfulStatusCodes()MoyaRxSwift提供的扩展方法,顾名思义,可以得到成功地网络请求,忽略其他的
  • mapJSON()也是Moya RxSwift的扩展方法,可以把返回的数据解析成 JSON 格式
  • subscribe 是一个RxSwift的方法,对经过一层一层处理的 Observable 订阅一个 onNextobserver,一旦得到 JSON 格式的数据,就会经行相应的处理
  • addDisposableTo(disposeBag)RxSwift 的一个自动内存处理机制,跟ARC有点类似,会自动清理不需要的对象。

4.配合HandyJSON

在实际应用过程中网络请求往往紧密连接着数据层(Model),具体地说,在我们的这个例子中,一般我们需要建立一个类用来统一管理数据,然后把得到的 JSON 数据映射到数据层(Model)。

struct MenuModel: HandyJSON {
var others: [ThemeModel]?
}
struct ThemeModel: HandyJSON {
var color: String?
var thumbnail: String?
var id: Int?
var description: String?
var name: String?
}

然后创建ViewModel类,创建具体请求方法:

class MenuViewModel { 

private let provider = RxMoyaProvider<APIManager>()
var dispose = DisposeBag()
func getThemes(completed: @escaping (_ menuModel: MenuModel) -> ()){ provider .request(.getThemes) .mapModel(MenuModel.self) .subscribe(onNext: { (model) in completed(model) }, onError: { (error) in }, onCompleted: nil, onDisposed: nil).addDisposableTo(dispose) } } 

这里解释一下: 我这里是将请求的数据通过闭包传了出去,当然也可以不那么做.个人喜好问题..

这里是为 RxSwift 中的 ObservableTypeResponse写一个简单的扩展方法 mapModel,利用我们写好的Model 类,一步就把JSON数据映射成 model

extension ObservableType where E == Response {
public func mapModel<T: HandyJSON>(_ type: T.Type) -> Observable<T> {
return flatMap { response -> Observable<T> in
return Observable.just(response.mapModel(T.self))
}
}
}
extension Response {
func mapModel<T: HandyJSON>(_ type: T.Type) -> T {
let jsonString = String.init(data: data, encoding: .utf8)
return JSONDeserializer<T>.deserializeFrom(json: jsonString)!
}
}

5.配合ObjectMapper

毕竟将json数据转换成model的库那么多 ….,所以……,用哪个很随意…..这里再介绍一下ObjectMapper

1.创建model类

class DetailModel: Mappable {
var body = String()
var image_source: String?
var title = String()
var image: String?
var share_url = String()
var js = String()
var recommenders = [[String: String]]()
var ga_prefix = String()
var section: DetailSectionModel?
var type = Int()
var id = Int()
var css = [String]()
func mapping(map: Map) {
body <- map["body"]
image_source <- map["image_source"]
title <- map["title"]
image <- map["image"]
share_url <- map["share_url"]
js <- map["js"]
recommenders <- map["recommenders"]
ga_prefix <- map["ga_prefix"]
section <- map["section"]
type <- map["type"]
id <- map["id"]
css <- map["css"]
}
required init?(map: Map) {
}
}

使用 ObjectMapper ,需要让自己的 Model 类使用 Mappable 协议,这个协议包括两个方法:

required init?(map: Map) {}
func mapping(map: Map) {}

mapping 方法中,用 <- 操作符来处理和映射你的 JSON数据。

数据类建立好之后,我们还需要为 RxSwift 中的 Observable 写一个简单的扩展方法 mapObject,利用我们写好的model 类,一步就把JSON 数据映射成一个个 model

extension Observable {
func mapObject<T: Mappable>(type: T.Type) -> Observable<T> {
return self.map { response in
//if response is a dictionary, then use ObjectMapper to map the dictionary
//if not throw an error
guard let dict = response as? [String: Any] else {
throw RxSwiftMoyaError.ParseJSONError
}
return Mapper<T>().map(JSON: dict)!
}
}
func mapArray<T: Mappable>(type: T.Type) -> Observable<[T]> {
return self.map { response in
//if response is an array of dictionaries, then use ObjectMapper to map the dictionary
//if not, throw an error
guard let array = response as? [Any] else {
throw RxSwiftMoyaError.ParseJSONError
}
guard let dicts = array as? [[String: Any]] else {
throw RxSwiftMoyaError.ParseJSONError
}
return Mapper<T>().mapArray(JSONArray: dicts)!
}
}
}
enum RxSwiftMoyaError: String {
case ParseJSONError
case OtherError
}
extension RxSwiftMoyaError: Swift.Error { }
  • mapObject 方法处理单个对象,mapArray 方法处理对象数组。
  • 如果传进来的数据 response 是一个 dictionary,那么就利用 ObjectMappermap方法映射这些数据,这个方法会调用你之前在 mapping方法里面定义的逻辑。
  • 如果 response 不是一个 dictionary, 那么就抛出一个错误。
  • 在底部自定义了简单的Error,继承了SwiftError类,在实际应用过程中可以根据需要提供自己想要的 Error

然后运行请求方法:

class DetailViewModel { private let provider = RxMoyaProvider<APIManager>() func getNewsDetail(id: Int) -> Observable<DetailModel> { return provider .request(.getNewsDetail(id)) .filterSuccessfulStatusCodes() .mapJSON() .mapObject(type: DetailModel.self) } } 

有没有感觉很爽呢!————源码地址,共同学习!

原文地址

有不对之处,,,,还望各路大神不吝指正!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/222962.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022年10月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.关于moya
  • 2.开始
  • 3.配合RxSwift
  • 4.配合HandyJSON
  • 5.配合ObjectMapper
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档