• 踩坑踩了4天总算把基于Moya的网络框架搭建完毕 看网上关于Moya的教程不太多,大多都是一样的,还有一些年久失修。这里专门讲讲关于moya的搭建及容易遇到的一些坑。 重要的东西放到最前面 1.最好的教材是官方文档和...

    踩坑踩了4天总算把基于Moya的网络框架搭建完毕

    看网上关于Moya的教程不太多,大多都是一样的,还有一些年久失修。这里专门讲讲关于moya的搭建及容易遇到的一些坑。

    重要的东西放到最前面

    1.最好的教材是官方文档和Demo,Moya有中文文档

    2.尝试一些不一样的东西会让开发更有趣。

    3.我把Demo地址放最后了。

    为什么选择moya:

    一开始网络框架的选型有Alamofire和Moya。

    Alamofire可以说是Swift版本的AFN,啃AFN的老啃了几年了,AFN的确博大精深,有很多值得开发者去学校的地方。但开发这么多年,AFN实在是啃不动了。试着封装了一下Alamofire。感觉和AFN封装大同小异。

    和技术群里的一些大佬讨论了一下,大多数也是推荐Moya,至于聊天记录里面提及的 包含?地址的问题 我们在稍后的内容里去解决。后来咬咬牙就决定使用Moya用新项目的网络框架。

    About Moya

    已经有大神把Moya的基本使用和各个模块的介绍说的很清楚了,这里就不赘述了,建议把框架的基本使用了解一番【iOS开发】Moya入坑记-用法解读篇

    上文作为入门是一篇不错的文章,但作为实际开发过程中,健壮全方位考虑的网络框架来说的来说还有很多用法并没有提及。 而且网上很多文章都是老版本,看的时候会感觉有些懵。。。所以我就写了本文?

    Let's Begin

    ####封装的目录结构

    安装好Moya后我们创建好三个空的Swift文件

    我们大致可将网络框架拆分成

    API.swift---将来我们的接口列表和不同的接口的一些配置在里面完成,最长打交道的地方。

    NetworkManager.swift---基本框架配置及封装写到这里

    MoyaConfig.swift---这个其实可有可无的,习惯上把baseURL和一些公用字符串放进来

    OK我们正式开始coding!

    API.swift中先创建一个API的枚举,枚举值是接口名, 并创建遵守TargetType协议的extention。

    这里我写三个测试的Api。第一个是无参,第二个是普通写法(我看官方文档好像是这种 多参数 都写进去的,实际开发过程中感觉有些麻烦),第三个是直接把所有参数包装成字典传进来的文艺写法。。

    直接点击错误代码补全即可自动补全所有的协议

    import Foundation
    import Moya
    
    enum API {
        case testApi//无参数的接口
        //有参数的接口
        case testAPi(para1:String,para2:String)//普遍的写法
        case testApiDict(Dict:[String:Any])//把参数包装成字典传入--推荐使用
    }
    
    extension API:TargetType{
        
        //baseURL 也可以用枚举来区分不同的baseURL,不过一般也只有一个BaseURL
        var baseURL: URL {
            return URL.init(string: "http://news-at.zhihu.com/api/")!
        }
        //不同接口的字路径
        var path: String {
            switch self {
            case .testApi:
                return "4/news/latest"
            case .testAPi(let para1, _):
                return "\(para1)/news/latest"
            case .testApiDict:
                return "4/news/latest"
    //        default:
    //            return "4/news/latest"
            }
        }
        
        /// 请求方式 get post put delete
        var method: Moya.Method {
            switch self {
            case .testApi:
                return .get
            default:
                return .post
            }
        }
        
        /// 这个是做单元测试模拟的数据,必须要实现,只在单元测试文件中有作用
        var sampleData: Data {
            return "".data(using: String.Encoding.utf8)!
        }
        
        /// 这个就是API里面的核心。嗯。。至少我认为是核心,因为我就被这个坑过
        //类似理解为AFN里的URLRequest
        var task: Task {
            switch self {
            case .testApi:
                return .requestPlain
            case let .testAPi(para1, _)://这里的缺点就是多个参数会导致parameters拼接过长
            //后台的content-Type 为application/x-www-form-urlencoded时选择URLEncoding            
                return .requestParameters(parameters: ["key":para1], encoding: URLEncoding.default)
            case let .testApiDict(dict)://所有参数当一个字典进来完事。
                //后台可以接收json字符串做参数时选这个
                return .requestParameters(parameters: dict, encoding: JSONEncoding.default)
    
            }
        }
        
        /// 设置请求头header
        var headers: [String : String]? {
            //同task,具体选择看后台 有application/x-www-form-urlencoded 、application/json
            return ["Content-Type":"application/x-www-form-urlencoded"]
        }
    }
    复制代码

    上面api.swift设置完毕

    NetworkManager.swift

    下面就开始构建我们的请求相关的东西 主要是完成对于Provider的完善及个性化设置。

    首先先看一个最简单的网络请求, 我们所有的请求都是来自于这个provider对象,测试一下 我们就能发出请求并拿到返回的结果。

            let provier = MoyaProvider<API>()
            provier.request(.testApi) { (result) in
                switch result {
                case let .success(response):
                    print(response)
                case let .failure(error):
                        print("网络连接失败")
                        break
                }
            }
    复制代码

    当然,对应情况复杂的项目这个是 远远不够滴! so~ 下面开始对provider进行改造

    先看看最丰满的provider是什么样子的

    当我看到这一个个扑朔迷离的参数时我的表情是这样的(⊙﹏⊙)b

    点进去看源码才发现Moya已经帮我们把每个参数都默认实现了一遍。我们可以根据自己的设计需求设置参数 每个参数什么意思也不赘述了,Moya 的初始化  这篇文章也都说了,建议初学者阅读一下。 ####需要指正的地方是:

    文中 endpointClosure 的使用举例中 target.parameters 已经没有这个属性了。现在版本的Moya用的task代替的。 Moya官方不希望在所有的请求中统一添加参数,不过我们可以自己去定义endPointClosure实现相应的效果 详情参照:Add additional parameters to all requests 里面有具体的解决方案。

    去除了不太常用的自定义stubClosure, callbackQueue, trackInflights后我的Provider长这样
    import Foundation
    import Moya
    import Alamofire
    import SwiftyJSON
    
    /// 超时时长
    private var requestTimeOut:Double = 30
    ///endpointClosure
    private let myEndpointClosure = { (target: API) -> Endpoint in
    ///这里的endpointClosure和网上其他实现有些不太一样。
    ///主要是为了解决URL带有?无法请求正确的链接地址的bug
        let url = target.baseURL.absoluteString + target.path
        var endpoint = Endpoint(
            url: url,
            sampleResponseClosure: { .networkResponse(200, target.sampleData) },
            method: target.method,
            task: target.task,
            httpHeaderFields: target.headers
        )
        switch target {
        case .easyRequset:
            return endpoint
        case .register:
            requestTimeOut = 5//按照项目需求针对单个API设置不同的超时时长
            return endpoint
        default:
            requestTimeOut = 30//设置默认的超时时长
            return endpoint
        }
    }
    
    private let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in
        do {
            var request = try endpoint.urlRequest()
            //设置请求时长
            request.timeoutInterval = requestTimeOut
            // 打印请求参数
            if let requestData = request.httpBody {
                print("\(request.url!)"+"\n"+"\(request.httpMethod ?? "")"+"发送参数"+"\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")")
            }else{
                print("\(request.url!)"+"\(String(describing: request.httpMethod))")
            }
            done(.success(request))
        } catch {
            done(.failure(MoyaError.underlying(error, nil)))
        }
    }
    
    /*   设置ssl
    let policies: [String: ServerTrustPolicy] = [
        "example.com": .pinPublicKeys(
            publicKeys: ServerTrustPolicy.publicKeysInBundle(),
            validateCertificateChain: true,
            validateHost: true
        )
    ]
    */
    
    // 用Moya默认的Manager还是Alamofire的Manager看实际需求。HTTPS就要手动实现Manager了
    //private public func defaultAlamofireManager() -> Manager {
    //    
    //    let configuration = URLSessionConfiguration.default
    //    
    //    configuration.httpAdditionalHeaders = Alamofire.SessionManager.defaultHTTPHeaders
    //    
    //    let policies: [String: ServerTrustPolicy] = [
    //        "ap.grtstar.cn": .disableEvaluation
    //    ]
    //    let manager = Alamofire.SessionManager(configuration: configuration,serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies))
    //    
    //    manager.startRequestsImmediately = false
    //    
    //    return manager
    //}
    
    
    /// NetworkActivityPlugin插件用来监听网络请求
    private let networkPlugin = NetworkActivityPlugin.init { (changeType, targetType) in
    
        print("networkPlugin \(changeType)")
        //targetType 是当前请求的基本信息
        switch(changeType){
        case .began:
            print("开始请求网络")
            
        case .ended:
            print("结束")
        }
    }
    
    // https://github.com/Moya/Moya/blob/master/docs/Providers.md  参数使用说明
    //stubClosure   用来延时发送网络请求
    
    let Provider = MoyaProvider<API>(endpointClosure: myEndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false)
    复制代码

    NetworkManager.swift 基本写完 还剩一点下面再说。

    这个时候我们的网络请求就会长这样:

            Provider.request(.testApi) { (result) in
                switch result {
                case let .success(response):
                    print(response)
                    //做相应的数据处理  这里我用的是HandyJson
                case let .failure(error):
                    print("网络连接失败")
                    //提示用户网络链接失败
                    break
                }
            }
    复制代码

    像我这种懒得一比的开发者,当然不想每一次都写这么多result判断。写好多重复的代码。

    于是我决定再次封装。。。

    来来,我们再次回到NetworkManager.swift 封装provider请求。

    思路:

    1.后台返回错误的时候我统一把errormsg显示给用户 2.只有返回正确的时候才把数据提取出来进行解析。 对应的网络请求的hud全部封装到请求里面。

    这个是针对于大多数请求。个别展示效果不同的请求自己老老实实用provider.request写就行。 下面我们在NetworkManager.swift中进行二次封装

    ///先添加一个闭包用于成功时后台返回数据的回调
    typealias successCallback = ((String) -> (Void))
    ///再次用一个方法封装provider.request()
    func NetWorkRequest(_ target: API, completion: @escaping successCallback ){
        //先判断网络是否有链接 没有的话直接返回--代码略
        
        //显示hud
        Provider.request(target) { (result) in
            //隐藏hud
            switch result {
            case let .success(response):
                do {
                    //这里转JSON用的swiftyJSON框架
                    let jsonData = try JSON(data: response.data)
                    //判断后台返回的code码没问题就把数据闭包返回 ,我们后台是0000 以实际后台约定为准。            
                    if jsonData[RESULT_CODE].stringValue == "0000"{
                        completion(String(data: response.data, encoding: String.Encoding.utf8)!)
                    }else{
                        //flag 不为0000 HUD显示错误信息
                        print("flag不为0000 HUD显示后台返回message"+"\(jsonData[RESULT_MESSAGE].stringValue)")
                    }
                } catch {
                }
            case let .failure(error):
                guard let error = error as? CustomStringConvertible else {
                    //网络连接失败,提示用户
                    print("网络连接失败")
                    break
                }
            }
        }
    }
    复制代码

    MoyaConfig.swift 这个就是丢一些公用字符串

    觉得麻烦可以放在NetworkManager.swift中 看个人爱好 代码如下

    
    import Foundation
    /// 定义基础域名
    let Moya_baseURL = "http://news-at.zhihu.com/api/"
    
    /// 定义返回的JSON数据字段
    let RESULT_CODE = "flag"      //状态码
    let RESULT_MESSAGE = "message"  //错误消息提示
    
    复制代码

    这个时候我们再去用封装好的网络工具优雅的进行网络请求

       NetWorkRequest(.testApi) { (response) -> (Void) in
              //用HandyJSON对返回的数据进行处理
            }
    复制代码

    github地址: github.com/Liaoworking…

    个人技术博客地址:liaoworking.com

    展开全文
  • 对于swift4.2的网络请求的封装。包含链式,类AFN及对moya封装封装的功能包含:1.一次性处理请求指示器HUD 2.一次性处理请求状态码及错误弹窗 3.登录过期自动跳转到登录页等。 4.可以处理所有接口都要使用的公共...
  • 网络请求是 App 中最常用的更能之一,除了 Apple 提供的 URLSession 之外,还有对其进行封装,功能更加强的的 Alamofire等强大的工具,尽管这样,我们依然会在自己的 App 中封装一套网络请求工具,以达到做网络请求时,代码...

    网络请求是 App 中最常用的更能之一,除了 Apple 提供的 URLSession 之外,还有对其进行封装,功能更加强的的 Alamofire等强大的工具,尽管这样,我们依然会在自己的 App 中封装一套网络请求工具,以达到做网络请求时,代码简洁高效.

    封装目的:

    做网络请求的时候尽量的简单,只需要少量的代码即可处理返回的数据

    封装过程:

    1.实现网络请求单例,提供可修改 baseURL和 get post 请求方法.

    enum RequestMethod {
        case post
        case get
    }
    ///请求对象 
    struct Requset {
        init(method: RequestMethod = .post, baseURL: String = "", path: String, parameters: [String : Any]?){
            self.method = method
            self.baseURL = baseURL
            self.path = path
            self.parameters = parameters ?? [:]
        }
        var method: RequestMethod
        var baseURL: String
        var path: String
        var parameters: [String: Any]
    }
    ///网络工具
    class NetworkManager {
        static let shared = NetworkManager("")
        init(_ baseURL: String = "") {
            self.baseUrl = baseURL
        }
        var baseUrl = ""
        func post(path: String,params: [String: Any]?,result: @escaping ((Result<Data,Error>)->())){
            let request = Requset(baseURL:baseUrl, path: path, parameters: params)
            let target = Target(request: request)
            self.request(target: target, result: result)
        }
        func get(path: String,params: [String: Any]?,result: @escaping ((Result<Data,Error>)->())){
            let request = Requset(baseURL:baseUrl, path: path, parameters: params)
            let target = Target(request: request)
            self.request(target: target, result: result)
        }
        private func request(target: Target,result: @escaping ((Result<Data,Error>)->())) {
            MoyaProvider<Target>().request(target) { (res) in
                switch res {
                case .success(let a):
                    result(.success(a.data))
                case .failure:
                    result(.failure(res.error!))
                }
            }
        }
    }
    复制代码

    现在已经可以做网络请求了,比如:把百度首页数据请求下来

    NetworkManager("https://www.baidu.com").get(path: "", params: nil) { (res) in
        let data = try! res.get()
        print(String(data: data, encoding: .utf8))
    }
    复制代码

    Optional("\r\n\r\n\r\n\r\n <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">\r\n <meta http-equiv="content-type" content="text/html;charset=utf-8">\r\n <meta content="always" name="referrer">\r\n <script src="ss1.bdstatic.com/5eN1bjq8AAU…">\r\n

    页面不存在_百度搜索\r\n ....

    2. 二次封装

    仅仅这样封装很明显不能够达到精简的目的,这样其实和直接使用 Alamofire 没啥区别.

    一般后台返回的数据都有固定的格式,比如:

    {
        "msg": "请求成功",
        "code": 1001,
        "data": {...}
    }
    或者:
    {
        "msg": "请求成功",
        "code": 1001,
        "data": [...]
    }
    复制代码

    将其转换成对应的模型:

    public struct DataResponse<T> {
        public init (){}
        public var code: Int = -1
        public var msg: String = ""
        public var data: T?
    }
    public struct ListResponse<T> {
        public init (){}
        public var code: Int = -1
        public var msg: String = ""
        public var data: [T] = []
    }
    复制代码

    我们实现一个 Protocol 继承自 HandyJSON (HandyJSON本身也是协议),然后是我们的 Response 遵守这个协议.

    public protocol RequestProtocol: HandyJSON {
        static func request(api: API, params: [String: Any]?, result: ((ResponseResult<Self>)->())?)
    }
    
    public extension RequestProtocol where Self: HandyJSON {
        static func request(api: API, params: [String: Any]?, result: ((ResponseResult<Self>)->())?) {
            let completionHandle: ((Result<Data,Error>)->()) = { res in
                switch res {
                case .success(let data):
                    let jsonStr = String(data: data, encoding: .utf8)
                    #if DEBUG
                    print("url: \(api.path)")
                    print("response:")
                    print(jsonStr ?? "")
                    #endif
                    ///不是 json 数据,抛出 json 解析失败错误
                    guard let jsonObj = self.self.deserialize(from: jsonStr) else {
                        result?(.failure(.deserializeFailed))
                        return
                    }
                    result?(.success(jsonObj))
                case .failure(_):
                    ///处理错误 抛出去
                    result?(.failure(.requestFailed))
                }
            }
            if api.method == .post {
                NetworkManager.shared.post(path: api.path, params: params, result: completionHandle)
            }else{
                NetworkManager.shared.get(path: api.path, params: params, result: completionHandle)
            }
        }
    }
    复制代码

    然后久可以如下优雅的做请求:

    NetworkManager.shared.baseUrl = "https://api.douban.com"
    BookResponse.request(api: .getBookDetail, params: nil) { (res) in
        guard res.isSuccess else { return }
        print(res.value?.toJSON())
    }
    复制代码

    {"msg":"invalid_apikey","code":104,"request":"POST /v2/book/1220562"}

    API 是这么样的结构体

    public struct API {
        var path: String
        var method: RequestMethod
        init(path: String, method: RequestMethod = .post) {
            self.path = path
            self.method = method
        }
    }
    ///可以通过这种方式 减少硬编码可能会带来的错误
    extension API {
        static let getBookDetail = API(path: "/v2/book/1220562")
    }
    复制代码

    Demo地址

    转载于:https://juejin.im/post/5cbd2475e51d456e2500050a

    展开全文
  • Moya基于Alamofire进行封装,使用更加简单,维护更加方便。 GitHub地址:https://github.com/Moya/Moya.git 1.使用CocoaPods导入Moya: pod 'Moya', '~&amp;gt; 11.0.2' 2.创建一个对象实现TargetType协议...

    GitHub地址:https://github.com/Moya/Moya.git
    Moya基于Alamofire进行封装,使用更加简单,维护更加方便。
    1.使用CocoaPods导入Moya:

    pod 'Moya', '~> 11.0.2'
    

    2.创建一个对象实现TargetType协议的方法

    import Foundation
    import Moya
    
    enum ScanServer {
        case qrLogin(appname: String, nonce: String, address: String)
        case qrLoginConfirm(appname: String, nonce: String, address: String, confirm: String)
    }
    
    extension ScanServer: TargetType {
        
        var headers: [String : String]? {
            return ["Content-type" : "application/json"]
        }
        
        var baseURL: URL {
            return URL(string: GlobalConfig.current.scanServerBase)!
        }
        
        var path: String {
            switch self {
            case .qrLogin(_):
                return "/qrlogin"
            case .qrLoginConfirm(_):
                return "/qrconfirm"
            }
        }
        
        var method: Moya.Method {
            switch self {
            case .qrLogin(_):
                return .get
            default:
                return .post
            }
        }
        
        var parameters: [String: Any]? {
            var paramsDict: [String : Any] = [:]
            switch self {
            case .qrLogin(let appname, let nonce, let address):
                paramsDict["appname"] = appname
                paramsDict["nonce"] = nonce
                paramsDict["address"] = address
            case .qrLoginConfirm(let appname, let nonce, let address, let confirm):
                paramsDict["appname"] = appname
                paramsDict["nonce"] = nonce
                paramsDict["address"] = address
                paramsDict["confirm"] = confirm
            }
            return paramsDict
        }
        
        var parameterEncoding: ParameterEncoding {
            return URLEncoding.default
        }
        
        var sampleData: Data {
            return "".data(using: .utf8)!
        }
        
        var task: Task {
            switch self {
            case .qrLogin(_):
                return .requestParameters(parameters: parameters ?? [:], encoding: URLEncoding.default)//get方式参数拼接成url
            default:
                return .requestParameters(parameters: parameters ?? [:], encoding: JSONEncoding.default)//post方式参数是json格式
            }
        }
        
    }
    
    

    3.创建一个对象实现MoyaProviderType协议的方法

    import Moya
    import Result
    import SwiftyJSON
    
    enum ProviderError: LocalizedError {
        case server
        case data
        case message(msg: String)
        
        var description: String {
            switch self {
            case .server:
                return "Failed to connect to server".localized
            case .data:
                return "Failed to get data".localized
            case .message(let msg):
                return msg
            }
        }
    }
    
    let networkPlugin = NetworkActivityPlugin { (change, _) in
        switch(change){
        case .ended:
            DispatchQueue.main.async {
                UIApplication.shared.isNetworkActivityIndicatorVisible = false
            }
        case .began:
            DispatchQueue.main.async {
                UIApplication.shared.isNetworkActivityIndicatorVisible = true
            }
        }
    }
    
    let scanClosure = { (endpoint: Endpoint, done: @escaping MoyaProvider<ScanServer>.RequestResultClosure) in
        do {
            var request: URLRequest = try endpoint.urlRequest()
            request.timeoutInterval = 30
            done(.success(request))
        } catch  {
            print("\(error)")
        }
    }
    
    class ScanProvider {
        
        static let shared = ScanProvider()
        
        let provider = MoyaProvider<ScanServer>(requestClosure: scanClosure, plugins: [networkPlugin])
        
        private func failureAction(error: ProviderError) {
            if NetworkingManager.status == .none || NetworkingManager.status == .unknown {
                Toast.showMessage(message: NetworkingManager.status.description)
            } else {
                Toast.showMessage(message: error.description)
            }
        }
        
        func qrLogin(appname: String,
                     nonce: String,
                     address: String,
                     completion: @escaping (Result<Bool, ProviderError>) -> Void) {
            provider.request(.qrLogin(
                appname: appname,
                nonce: nonce,
                address: address)) { result in
                    switch result {
                    case .success(let responseData):
                        if let response = JSONResponseFormatter(responseData.data) {
                            print(response)
                            if let status = response["state"] as? Int {
                                completion(.success(status == 1 ? true : false))
                            }
                        }
                    case .failure(_):
                        self.failureAction(error: .server)
                        completion(.failure(.server))
                    }
            }
        }
        
        func qrLoginConfirm(appname: String,
                            nonce: String,
                            address: String,
                            confirm: String,
                            completion: @escaping (Result<Bool, ProviderError>) -> Void) {
            provider.request(.qrLoginConfirm(
                appname: appname,
                nonce: nonce,
                address: address,
                confirm: confirm)) { result in
                    switch result {
                    case .success(let responseData):
                        if let response = JSONResponseFormatter(responseData.data) {
                            print(response)
                            if let status = response["state"] as? Int {
                                completion(.success(status == 1 ? true : false))
                            }
                        }
                    case .failure(_):
                        self.failureAction(error: .server)
                        completion(.failure(.server))
                    }
            }
        }
    }
    

    4.发起请求

    ScanProvider.shared.qrLogin(
        appname: result.qrStringAppName,
        nonce: result.qrStringNonce,
        address: result.address
    ) {[weak self] (res) in
        guard let `self` = self else { return }
        switch res {
        case .success(_):
            print("success")
        case .failure(_):
            print("failure")
        }
    }
    
    展开全文
  • Moya使用demoMoya面向协议Moya的模块组成代码demo Moya Moya是一个网络抽象层,它在底层将Alamofire进行封装,对外提供更简洁的接口供开发者调用。在Objective-C中,大部分开发者会使用AFNetwork进行网络请求,当...

    Moya

    Moya是一个网络抽象层,它在底层将Alamofire进行封装,对外提供更简洁的接口供开发者调用。在Objective-C中,大部分开发者会使用AFNetwork进行网络请求,当业务复杂一些时,会对AFNetwork进行二次封装,编写一个适用于自己项目的网络抽象层。在Objective-C中,有著名的YTKNetwork,它将AFNetworking封装成抽象父类,然后根据每一种不同的网络请求,都编写不同的子类,子类继承父类,来实现请求业务。Moya在项目层次中的地位,有点类似于YTKNetwork。可以看下图对比
    网络请求层级
    如果单纯把Moya等同于swift版的YTKNetwork,那就是比较错误的想法了。Moya的设计思路和YTKNetwork差距非常大。上面我在介绍YTKNetwork时在强调子类和父类,继承,是因为YTKNetwork是比较经典的利用OOP思想(面向对象)设计的产物。基于swiftMoya虽然也有使用到继承,但是它的整体上是以POP思想(Protocol Oriented Programming,面向协议编程)为主导的。

    面向协议

    请看我的其中一篇文章有介绍到

    Moya的模块组成

    Moya层级

    1. Provider:provider是一个提供网络请求服务的提供者。通过一些初始化配置之后,在外部可以直接用provider来发起request。
    2. Request:在使用Moya进行网络请求时,第一步需要进行配置,来生成一个Request。首先按照官方文档,创建一个枚举,遵守TargetType协议,并实现协议所规定的属性。为什么要创建枚举来遵守协议,枚举结合switch语句,使得API管理起来比较方便。
    3. 根据创建了一个遵守TargetType协议的名为Myservice的枚举,我们完成了如下几个变量的设置。
    	baseURL
    	path
    	method
    	sampleData
    	task
    	headers
    

    代码demo

    //
    //  YShareApI.swift
    //  
    //
    //  Created by bruce yao on 2019/4/10.
    //  Copyright © 2019 bruce yao. All rights reserved.
    //
    
    import UIKit
    import Moya
    import RxCocoa
    import Result
    import SwiftyJSON
    
    //初始rovider
    let YShareApiProvider = MoyaProvider<YShareAPI>(plugins: [RequestLoadingPlugin()])
    
    /** 请求的endpoints)**/
    //请求分类
    enum YShareAPI {
        case shareNavList:
        case shareList(pageSize: Int, pageNum: Int):
    }
    //请求配置
    extension YShareAPI: TargetType {
        //服务器地址
        public var baseURL: URL {
            switch self {
            default:
                return URL(string: HD_Search_Base)!
            }
        }
        
        //各个请求的具体路径
        public var path: String {
            switch self {
            case .shareNavList:
                return "manage/navigation/getNavigationList"
            default:
                return "ddddd/list"
            }
        }
        
        //请求类型
        public var method: Moya.Method {
            switch self {
           
            default:
                return .get
            }
        }
        
        //请求任务事件(这里附带上参数)
        public var task: Task {
            switch self {
            case .shareNavList:
                return .requestPlain
           case .shareList(let pageSize, let pageNum):
                var params: [String: Any] = [:]
                params["pageSize"] = pageSize
                params["pageNum"] = pageNum
                return .requestParameters(parameters: params, encoding: URLEncoding.default)
            }
        }
        //是否执行Alamofire验证
        public var validate: Bool {
            return false
        }
        //这个就是做单元测试模拟的数据,
    //    只会在单元测试文件中有作用
        public var sampleData: Data {
            return "{}".data(using: String.Encoding.utf8)!
        }
    
        //请求头
        public var headers: [String: String]? {
            switch self {
            default:
                return ["Content-type": "application/json"]
            }
        }
    }
    
    //
    //  RequestLoadingPlugin.swift
    //  
    //
    //  Created by bruce yao on 2019/1/25.
    //  Copyright . All rights reserved.
    //
    
    import UIKit
    import Foundation
    import MBProgressHUD
    import Moya
    import Result
    
    class RequestLoadingPlugin: PluginType {
        
        func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
            print("prepare")
            var mRequest = request
            mRequest.timeoutInterval = 20
            return mRequest
        }
        func willSend(_ request: RequestType, target: TargetType) {
            print("开始请求")
            if SwiftIsShowHud == true {
                let keyViewController = UIApplication.shared.keyWindow?.rootViewController
                if (keyViewController != nil) {
                    MBProgressHUD.showAdded(to: keyViewController!.view, animated: true)
                }
            }
            
        }
        
        func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {
            print("结束请求")
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.hide(for: keyViewController!.view, animated: true)
                //            MBProgressHUD.
            }
            
            
           guard case Result.failure(_) = result
            else {
                let respons = result.value
                let dic: Dictionary<String, Any>? =
                    try? JSONSerialization.jsonObject(with: respons!.data, options: .mutableContainers) as! Dictionary<String, Any>
                
                if dic != nil {
                    if dic?.keys.contains("status") == true {
                        if dic?["status"] as! Int == 11 || dic?["status"] as! Int == 12 {
                            print("Token 失效")
                        }
                    }
                    
                    if dic?.keys.contains("code") == true {
                        if dic?["code"] as! Int == 11 || dic?["code"] as! Int == 12 {
                            print("Token 失效")
                        }
                    }
                }
                return
            }
            let errorReason: String = (result.error?.errorDescription)!
            print("请求失败:\(errorReason)")
            var tip = ""
            if errorReason.contains("The Internet connection appears to be offline") {
                tip = "网络不给力,请检查您的网络"
            }else if errorReason.contains("Could not connect to the server") {
                tip = "无法连接服务器"
            }else {
               tip = "请求失败"
            }
            /// 使用tip文字 进行提示
        }
    }
    

    Controller中使用

    代码片段

    import RxSwift
    import RxCocoa
    import ObjectMapper
    
    YShareApiProvider
                    .rx.request(input.category)
                    .mapObject(YBaseModel<T>.self)
                    .subscribe(onSuccess: { (baseModel) in
                        print("请求成功 返回数据如下")
                        if baseModel.status != 0 {
                            
                            return
                        }
                        
                    }, onError: {error in
                        print("Error:请求错误")
                       
                    }).disposed(by: self.disposeBag)
                }, onError: { (error) in
                    
            }, onCompleted: {
                
            }) {
                
                }.disposed(by: disposeBag)
    
    展开全文
  • swift moya和ObjectMapper

    2018-05-05 00:47:13
    Moya 使用moya主要是因为网上说这是一个比较推荐的swift开源项目,当一开始学习时看见使用说明就有点扭头要走的冲动,本来一个简单的客户端http request代码分成了好多小块来处理,不过看在有名气的份上还是选择...

    Moya


    使用moya主要是因为网上说这是一个比较推荐的swift开源项目,当一开始学习时看见使用说明就有点扭头要走的冲动,本来一个简单的客户端http request代码分成了好多小块来处理,不过看在有名气的份上还是选择用它。稍试用了一下发现这其实就像一个web服务器框架,按它的规则往里面填空就可以了,只不过我们平常很少在http客户端使用类似的框架。

    另外吐槽一下rxswift,这是因为moya也支持rxswift才想起来的。说实话虽然对于rxswift不怎么了解但是崇尚简单的我觉得学习rxswift就是多此一举,本来连swift我都觉得有点繁琐,没事还搞这么重的一层框架干嘛,非得在一种新语言里搞另一种编程范式,真是吃饱了撑的。

    Swift - 网络抽象层库Moya的使用详解1(安装配置、基本用法)
    Swift - 网络抽象层库Moya的使用详解2(请求参数说明)
    Swift - 网络抽象层库Moya的使用详解3(请求成功、失败的结果处理)
    Swift - 网络抽象层库Moya的使用详解4(单文件上传:文件流方式)
    Swift - 网络抽象层库Moya的使用详解5(多文件上传:MultipartFormData方式)
    Swift - 网络抽象层库Moya的使用详解6(文件下载、资源下载器)
    Swift - 网络抽象层库Moya的使用详解7(多个target使用同一个Provider)
    Swift - 网络抽象层库Moya的使用详解8(创建自定义插件)

    ObjectMapper


    Swift - 使用ObjectMapper实现模型转换1(JSON与Model的相互转换)
    Swift - 使用ObjectMapper实现模型转换2(StaticMappable协议)
    Swift - 使用ObjectMapper实现模型转换3(高级用法)
    Swift - 使用ObjectMapper实现模型转换4(与Alamofire结合使用)

    展开全文
  • HHPGNetWork Moya二次封装,支持流失请求和RxSwift请求,附带HandyJSON实现对象解析 cocoapods: pod 'HHPGNetWork' github 地址 https://github.com/manfengjun/HHPGNetWork
  • Moya是一个网络抽象层,它在底层将Alamofire进行封装,对外提供更简洁的接口供开发者调用。在Objective-C中,大部分开发者会使用AFNetwork进行网络请求,当业务复杂一些时,会对AFNetwork进行二次封装,编写一个适用...
  • MoyaSwift开发中起着重要的网络交互作用,但是还有不如之处,比如网络不可用时,返回的 Response 为 nil,这时还得去解析相应的 Error Codable 可以帮助我们快速的解析数据,但是一旦声明的属性类型与json中的不...
  • MoyaSwift中的网络库Alamofire的二次封装,Alamofire本身使用起来是很简单方便的,例子如下: func loadData(){ var param = [String:String]() param["pageNo"] = "1" param["...
  • 封装了个网络请求库、但是想要手动解析、调出了方法、需要处理的是response中的data数据了 NetWorking是自己封装的类的名字 let ApiProvider = MoyaProvider<NetWorking>(requestClosure:timeoutClosure) ...
  • RxSwift学习之十一 (Rxswift+Moya+Alamofire)
  • 在使用Alamofire进行网络请求的时候,相信大部分的同学都会封装一个抽象的NetworkLayer,如"APIManager" 或者 "NetworkModel"等等。但是位置业务功能增加,会渐渐混合各种请求,不够清晰,而Moya能很好地解决这类...
  • 如何写出最简洁优雅的网络封装 Moya + RxSwift
  • import UIKitimport Alamofireimport SwiftyJSON/** 请求成功回调*/typealias NetSuccessBlock = (NSDictionary,SwiftyJSON.JSON) -&gt; Void/** 请求失败回调*/typealias NetFaliedBlock = (AFSErrorInfo) -&...
  • Swift Moya

    2015-12-17 17:31:46
    但是,如果你直接使用的话,会使得各种网络请求操作分布很凌乱,所以我选择了巧神封装的YTKNetwork,很好用,有兴趣的可以看一下.当然你也可以自己组织封装. 这段代码就是LZ项目中的网络请求: NSDictionary *...
  • 一个对AFN网络框架的简单封装,具有网络请求过程的日志打印功能
  • 文章目录开源项目分析(SwiftHub)架构分析(一)1. SwiftHub项目简介2. SwiftHub项目采用的架构 开源项目分析(SwiftHub)架构分析(一) 1. SwiftHub项目简介 2. SwiftHub项目采用的架构 ...
1 2 3 4 5 ... 12
收藏数 233
精华内容 93