moya + RxSwift 进行网络请求

moya + RxSwift 进行网络请求1.关于moya如在OC中使用AFNetworking一般,Swift我们用Alamofire来做网络库.而Moya在Alamofire的基础上又封装了一层:官方说moya有以下特性(我也就信了):编译时检查正确的API端点访问.使你定义不同端点枚举值对应相应的用途更加明晰.提高测试地位从而使单元测试更加容易.2.开始1.创建枚举API就像这样:enumAPIManager{c

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

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

1.关于moya

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

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) } } 

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

原文地址

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

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • webstorm2021 永久激活码(JetBrains全家桶)

    (webstorm2021 永久激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容https://javaforall.cn/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~2JTX0APX6F-eyJsaWNlb…

  • 微信小程序解析富文本标签[通俗易懂]

    微信小程序解析富文本标签[通俗易懂]wxParse方法我踩雷了微信官方文档有个更为便捷的标签<rich-textnodes=”{{}}”></rich-text>

  • matlab产生高斯白噪声

    matlab产生高斯白噪声函数介绍matlab里和随机数有关的函数:(1)rand:产生均值为0.5、幅度在0~1之间的伪随机数。(2)randn:产生均值为0、方差为1的高斯白噪声。(3)randperm(n):产生1到n的均匀分布随机序列。(4)normrnd(a,b,c,d):产生均值为a、方差为b大小为cXd的随机矩阵。rand:返回一个在区间(0,1)内均匀分布的随机数。rand(n):生成0到1之间的n阶(n×n)随机数方阵。rand(m,n):生成0到1之间的m×n的随机数矩阵。

    2022年10月21日
  • java图书馆新地址_值得你关注的16个顶级 Java 开源项目!小白必看

    java图书馆新地址_值得你关注的16个顶级 Java 开源项目!小白必看1.JavaGuide把这个排第一没有个人因素影响哈!Guide哥我自己大三开始维护的,目前算是纯Java类型项目中Star数量最多的项目了。但是,本仓库的价值远远(+N次)比不上像SpringBoot、Elasticsearch等等这样非常非常非常优秀的项目。希望以后我也有能力为这些项目贡献一些有价值的代码。Github地址:https://github.com/Snailc…

  • vue怎么使用layui_layui动态添加输入框

    vue怎么使用layui_layui动态添加输入框vue-layer弹框插件安装npmi–savevue-layer引用importlayerfrom’vue-layer’Vue.prototype.$layer=layer(Vue);参数说明{type:0,//0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)title:’信息’,con…

    2022年10月24日
  • stuffing list_difflib

    stuffing list_difflibhttps://blog.csdn.net/heimu24/article/details/535813621.2创建图片列表清单这一步我们需要创建自己图片数据集的清单txt文件,这里提供两种方法。方法1:创建一个sh文件cd~/caffe-master/sudogeditexamples/images/create_filelist.shsudo就是获取管理员权限,gedit…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号