Alamofire+HandyJSON+泛型封装的简单离散式网络框架

Posted Androider_Zxg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Alamofire+HandyJSON+泛型封装的简单离散式网络框架相关的知识,希望对你有一定的参考价值。

离散式与集约式网络框架

集约式:

每个请求都会走统一的入口,对外暴露了请求的 URL 和 Param 以及请求方式,入口一般都是通过单例 来实现。例如

HttpClient.getInstance().sendRequest(url,params,callback)

优点:

1、使用便捷,可以快速开发

缺点:

1、对每个请求的定制要求不够,例如,现在有个新需求,请求新闻条目需要保存网络缓存,但其他网络请求不需要。那么我们必须新开一个sendRequest()方法,其中加一个参数isCache。这种情况对后期业务扩展非常不友好。

离散式:

即每个网络请求类都是一个对象,它的 URL 以及请求方式和响应方式 均不暴露给外部调用。只能内部通过 重载或实现协议 的方式来指定,例如ios中的YTKNetWork即是这种方式。思想是为每一个请求编写一个配置类,在该类中重写接口(协议)中定义的方法返回该网络请求需要的参数。

优点:

1、扩展性强

2、URL 以及请求和响应方式不暴露给外部,避免外部调用的时候写错,设想一下,使用集约式设计,我们所有的URL地址均写在一个类似URLContants的文件中,那么新增、修改、删除url都需要修改该文件,大大提高了出错风险。

3、可定制性强,可以为每个请求指定请求的超时时间以及缓存的周期

缺点:

每个网络请求都要配置一个类,业务丰富后类数量较多

好,有了简单的概念了解后,我们进入正题,设计一套离散式的网络框架

 

swift离散式网络框架

1、框架性代码HttpRestfulClient

核心类,封装第三方网络请求库,暴露请求方式,是单例。我就将代码完全粘进来了,保证同学能看得懂

//
//  HttpRestfulClient.swift
//  HelloIOS
//
//  Created by zxg on 2018/10/29.
//  Copyright © 2018年 zxg. All rights reserved.
//

import UIKit
import Alamofire
import SwiftyJSON
import HandyJSON

class HttpRestfulClient 
    static let sharedInstance = HttpRestfulClient()
    
    private init() 
    //    let device_id: Int = 6096495334
    //    let iid: Int = 5034850950

    
    //Demo
    //这里使用了逃逸闭包,因为responseJson为异步,所以当网络请求结果回来后,事实上testRequest()方法已经执行完了。那么
    //传入函数testRequest()的闭包是在testRequest()函数执行完后,才要执行的,也就是说这个闭包已经逃逸到函数外部了。所以要加该注解
    //swift3.0默认是非逃逸的
    //弊端
    //该方法拿到数据后,字节解析字段,破坏了封装性。合理的做法应该是封装成model,再调用闭包,把model给出去
    public func testRequset<T:HandyJSON>(_ completionHandler: @escaping(_ dataFromNet:AnyObject)->(),_ protocol:BaseProtocol<T>)
        //        let params = ["device_id": device_id, "iid": iid]
        //        Alamofire.request("https://is.snssdk.com/search/suggest/homepage_suggest/?", method: .get, parameters params).responseString
        //            (response) in
        //            if let value = response.result.value
        //                print("value:",value5034850950)
        //                let json = JSON(value)
        //                print(json)
        //                guard json["message"] == "success" else return
        //
        //                if let data = json["data"].dictionary
        //                    completionHandler(data["homepage_search_suggest"]!.string!)
        //                
        //                let responseModel = BaseResponse<T>.deserialize(from: value)!
        //                print("model:",responseModel.data)
        //                completionHandler((responseModel.data as? AnyObject)!)
        //            
        //        
    
    
    //网络请求函数,参数固定,所有网络请求参数放在netProtocol中,即使以后扩展
    //也不需要改变接口
    public func sendRequset<T:HandyJSON>(_ netProtocol:BaseProtocol<T>,_ competionHandler:@escaping(_ model:AnyObject?,_ error:NetError)->())
        var error:NetError = NetError.SUCCESS
        Alamofire.request(netProtocol.getOpertion()!,
                          method: transformMethod(netProtocol.getMethod()),
                          parameters: netProtocol.getParams()).responseString
                            (response) in
                            if let value = response.result.value
                                print("value:",value)
                                let responseModel = BaseResponse<T>.deserialize(from: value)!
                                if(responseModel.message! != "success")
                                    error = NetError.DATA_ERROR
                                
                                competionHandler(responseModel.data as? AnyObject,error)
                            
        
    
    
    //自定义NetMethod转Alamofire.HTTPMethod,目的是对上层完全隐藏Alamofire,这样即使换掉Alamofire框架
    //上层也不需要改动
    private func transformMethod(_ method:NetMethod)->HTTPMethod
        switch method 
        case .GET:
            return HTTPMethod.get
        case .POST:
            return HTTPMethod.post
        default:
            return HTTPMethod.get
        
    
    
    enum NetError:Int
        case SUCCESS = 0;
        case DATA_ERROR = 1;
    
    
    enum NetMethod:Int
        case GET = 10;
        case POST = 20;
    

框架性代码BaseProtocol

该类作为sendRequest()的核心参数,封装网络请求参数,业务层开发时,不同的网络请求均要实现这样一个类

//
//  BaseProtocol.swift
//  HelloIOS
//
//  Created by zxg on 2018/10/29.
//  Copyright © 2018年 zxg. All rights reserved.
//

import UIKit
import HandyJSON

class BaseProtocol<T:HandyJSON> 
    //返回网络请求参数
    func getParams()->Dictionary<String, AnyObject>?
        return nil;
    
    
    //返回网络地址url
    func getOpertion()->String?
        return nil
    
    
    //返回请求方法
    func getMethod()->HttpRestfulClient.NetMethod
        return HttpRestfulClient.NetMethod.GET
    
    
    //以后可以增加接口

    public required init()

框架性代码BaseResponse

用于使用HandyJSON进行Json解析,HandyJSON和Gson很像,都是采用反射、泛型等技术进行json与model的映射,不需要手动解析每一个字段,这里使用泛型,也是为了外部在调用时,通过泛型将需要映射成的目标model类传进来,sendRequest内部进行解析。其实也可以直接将jsonStr抛给netProtocol,让解析response这个动作也离散式的分解到每一个protocol中。而封装BaseResponse的目的是做一些通用逻辑,例如在进行Model转换前,判断message是否为success。是success再进行model转换否则抛出error

//
//  BaseResponse.swift
//  HelloIOS
//
//  Created by zxg on 2018/10/31.
//  Copyright © 2018年 zxg. All rights reserved.
//

import Foundation
import HandyJSON

class BaseResponse<T>:HandyJSON
    var message:String?
    var data:T?
    public required init()

业务性代码

这里我们站在业务端角度,使用一下该简单框架,网络请求的名字就叫TestNet吧

为本次网络请求配置Protocol类:TestNetProtocol

//
//  TestNetProtocol.swift
//  HelloIOS
//
//  Created by zxg on 2018/11/1.
//  Copyright © 2018年 zxg. All rights reserved.
//

import Foundation
import HandyJSON

class TestNetProtocol:BaseProtocol<TestNetResponse>
    var device_id:Int=0
    var iid:Int=0
    
    override func getParams()->Dictionary<String, AnyObject>?
        return ["device_id": device_id as AnyObject, "iid": iid as AnyObject];
    
    
    override func getOpertion()->String?
        return "https://is.snssdk.com/search/suggest/homepage_suggest/?"
    

    override func getMethod() -> HttpRestfulClient.NetMethod 
        return HttpRestfulClient.NetMethod.GET
    
    required init()
        super.init()
    

Response类

//
//  TestNetResponse.swift
//  HelloIOS
//
//  Created by zxg on 2018/10/31.
//  Copyright © 2018年 zxg. All rights reserved.
//

import Foundation
import HandyJSON
class TestNetResponse:HandyJSON
    var call_per_refresh:Int?
    var homepage_search_suggest:String?
    var suggest_words:[SuggestWord]?
    required init()


class SuggestWord:HandyJSON
    var id:Int?
    var or:String?
    var word:String?
    required init()

在Controller中调用

    //测试访问网络
    @IBAction func testNet(_ sender: Any) 
        prot.device_id = 6096495334
        prot.iid = 5034850950
        print("testNetWork click")
        HttpRestfulClient.sharedInstance.sendRequset(prot,(model,error) in
            if error != HttpRestfulClient.NetError.SUCCESS 
                print("error")
                return
            
            if let data = model as? TestNetResponse
                self.updateUI(model: data)
            
        )
    

    private func updateUI(model:TestNetResponse)
        self.tvNetData.text = model.homepage_search_suggest!
    

网络返回的json:

testNetWork click
value: "data":"call_per_refresh":1,"homepage_search_suggest":"劳森 | 今晚中国女排直播5 | 古德洛克","suggest_words":["id":"6538744360526157064","or":"qcrs:65","word":"劳森","id":"6605143180503422221","or":"qc:349 qcrs:15","word":"今晚中国女排直播5","id":"6573947909807592707","or":"qcrs:66","word":"古德洛克"],"message":"success"

后记

逻辑比较简单,没有处理缓存、header头等逻辑,仅仅是为了展示离散式网络访问思想的优点,以及练习下swift的泛型、闭包等技术。如果有时间,后期会丰富。

以上是关于Alamofire+HandyJSON+泛型封装的简单离散式网络框架的主要内容,如果未能解决你的问题,请参考以下文章

Swift 运用协议泛型封装网络层

Swift handyJson使用原理

Alamofire的简单封装

阿里巴巴最新开源项目 - [HandyJSON] 在Swift中优雅地处理JSON

使用HandyJSON导致的内存泄漏问题相关解决方法

swift4.1升级到 HandyJSON crash