博客> Moya网络层 + ObjectMapper数据转模型
Moya网络层 + ObjectMapper数据转模型
2018-09-24 14:35 评论:0 阅读:190 r17

Swift中的网络请求库 Alamofire,相当于OC中的 AFNetworking,在使用的过程中,我们一般都会对Alamofire做进一步的封装,可是结果有时不太理想。

所以就引出了 Moya,它是一个网络抽象层,封装的比较充分,并且是直接调用Alamofire,借用一下Moya的图如下。

Moya

完成网络请求拿到JSON数据之后,通常都需要转模型,所以本文顺带介绍一下 ObjectMapper 的基本使用方法。

本文Demo的GitHub地址:MoyaDemo

一、Moya的使用方法

1、创建网络层.swift文件

这里我创建了一个WHService.swift文件,并导入头文件import Moya

创建swift.文件

2、定义网络请求接口

实际上是定义一个枚举,枚举名就是每个网络请求API。

// 定义请求方法
enum WHService {
    case demo1
    case demo2(name: String)
    case demo3(name: String, score: Int)
}

3、扩展遵守协议,并实现协议方法

这一步我们创建一个扩展,并遵守TargetType协议,这个协议中有几个方法需要实现,具体意义看下面代码中的注释

extension WHService: TargetType {

    // 请求服务器的根路径
    var baseURL: URL { return URL.init(string: "https://httpbin.org")! }

    // 每个API对应的具体路径
    var path: String {
        switch self {
        case .demo1:
            return "/get"
        case .demo2(name: _), .demo3(name: _, score: _):
            return "/post"
        }
    }

    // 各个接口的请求方式,get或post
    var method: Moya.Method {
        switch self {
        case .demo1:
            return .get
        case .demo2, .demo3:
            return .post
        }
    }

    // 请求是否携带参数,如果需要参数,就做如demo2和demo3的设置
    var task: Task {
        switch self {
        case .demo1:
            return .requestPlain // 无参数
        case let .demo2(name): // 带有参数,注意前面的let
            return .requestParameters(parameters: ["name" : name], encoding: URLEncoding.default)
        case let .demo3(name, score): // 带有参数,注意前面的let
            return .requestParameters(parameters: ["name" : name, "score" : score], encoding: URLEncoding.default)
        }
    }

    // 单元测试使用
    var sampleData: Data {
        switch self {
        case .demo1, .demo3:
            return "just for test".utf8Encoded
        case .demo2(let name):
            return "{\"name\": \(name)\"}".utf8Encoded
        }
    }

    // 请求头
    var headers: [String : String]? {
        return ["Content-type" : "application/json"]
    }
}

4. 实现网络请求(推荐第5步的做法,可以忽略本条,直接查看第5步)

如下代码所示,首先创建一个MoyaProvider,并跟上, 然后直接调用request方法请求数据。

注意:request方法的参数就是上面定义的方法枚举,由此调用不同的API。达到了把网络请求封装到了WHService.swift中的需求。

        let provider = MoyaProvider<WHService>()

        provider.request(.demo1) { (result) in
            switch result {
            case let .success(moyaResponse):
                let data = moyaResponse.data // 获取到的数据
                let statusCode = moyaResponse.statusCode // 请求状态: 200, 401, 500, etc

            case let .failure(error):
                print(error.localizedDescription)
            }
        }

5. 创建Network结构体实现网路请求

在WHService.swift中创建一个WHNetwork结构体,用单例创建MoyaProvider。

这样的好处是,可以在任何需要的地方通过WHNetwork调用任意API。

// 网络请求结构体
struct WHNetwork {

    // 请求成功的回调
    typealias successCallback = (_ result: Any) -> Void
    // 请求失败的回调
    typealias failureCallback = (_ error: MoyaError) -> Void

    // 单例
    static let provider = MoyaProvider<WHService>()

    // 发送网络请求
    static func request(
        target: WHService,
        success: @escaping successCallback,
        failure: @escaping failureCallback
        ) {

        provider.request(target) { result in
            switch result {
            case let .success(moyaResponse):
                do {
                    try success(moyaResponse.mapJSON()) // 测试用JSON数据
                } catch {
                    failure(MoyaError.jsonMapping(moyaResponse))
                }
            case let .failure(error):
                failure(error)
            }
        }
    }
}

完成了WHService.swift中的工作之后,现在我们在ViewController.swift中进行网络访问,来看一下效果。

override func viewDidLoad() {
        super.viewDidLoad()

        WHNetwork.request(target: .demo1, success: { (result) in
            whLog(result)
        }) { (error) in
            whLog(error.localizedDescription)
        }

        WHNetwork.request(target: .demo2(name: "wuhao"), success: { (result) in
            whLog(result)
        }) { (error) in
            whLog(error.localizedDescription)
        }

        WHNetwork.request(target: .demo3(name: "wuhao", score: 100), success: { (result) in
            whLog(result)
        }) { (error) in
            whLog(error.localizedDescription)
        }

显然比较简洁,并且用闭包的方式获取到需要的数据。

二、ObjectMapper的使用方法

1. 创建模型文件

2. 配置模型文件

首先来看一个网络请求拿到的数据

{
    args =     {
    };
    headers =     {
        Accept = "*/*";
        "Accept-Encoding" = "gzip;q=1.0, compress;q=0.5";
        "Accept-Language" = "en;q=1.0";
        Connection = close;
        "Content-Type" = "application/json";
        Host = "httpbin.org";
        "User-Agent" = "MoyaDemo/1.0 (com.wuhao.MoyaDemo; build:1; iOS 11.2.0) Alamofire/4.7.0";
    };
    origin = "58.38.42.32";
    url = "https://httpbin.org/get";
}

下面开始写文件中的代码

创建几个需要的模型属性,导入ObjectMapper头文件,然后遵守Mappable协议,并实现两个协议方法。

func mapping(map: Map)方法就是映射属性,格式就是:属性名 -> map["数据中对应的名称"]。

如果想拿到上面数据中headers里的Host,运用点语法的方式就可以:map["headers.Host"]

完整的模型文件代码如下:

import UIKit
import ObjectMapper

class Internet: Mappable {

    var origin: String = ""
    var url: String = ""
    var Connection: String = ""
    var Host: String = ""
    var Agent: String = ""

    required init?(map: Map) {

    }

    func mapping(map: Map) {
        origin      <- map["origin"]
        url         <- map["url"]
        Connection  <- map["headers.Connection"]
        Host        <- map["headers.Host"]
        Agent       <- map["headers.User-Agent"]
    }
}

3. 数据转模型

在网络请求拿到数据之后,可以直接进行转模型。 调用模型类的 Internet(JSON: [String : Any]) 方法实现转模型操作。

        WHNetwork.request(target: .demo1, success: { (result) in
            // 字典转模型
            guard let internet = Internet(JSON: (result as! [String : AnyObject])) else { return }
            // 打印模型中值来验证是否成功
            whLog(internet.origin)
            whLog(internet.url)
            whLog(internet.Connection)
            whLog(internet.Host)
            whLog(internet.Agent)
        }) { (error) in
            whLog(error.localizedDescription)
        }

运用ObjectMapper来转模型还是很好用的。


后记

本文Demo地址: MoyaDemo

我的 GitHub

收藏
0
sina weixin mail 回到顶部