swift网络请求

swift同样可以实现OC中AFNetworking+MJExtension的效果,实现方法是Alamofire+SwiftyJSON+HandyJSON

Alamofire:网络请求
SwiftyJSON:数据解析
HandyJSON:映射为model

一、获取SessionManager子类的单例

节约系统开支不用每次网络请求都生成一个SessionManager子类对象

//
//  TMNetManager.swift
//  ivygateCRM
//
//  Created by 纪志刚 on 2018/7/27.
//  Copyright © 2018年 纪志刚. All rights reserved.
//

import UIKit
import Alamofire


/// 网络配置单例类
class TMNetManager: SessionManager {
    
    static var theManager:TMNetManager?
    
    class func shareManager(timeOutFlo:TimeInterval = 60) -> TMNetManager {
        
        let config = Config.shareConfig()
        config.timeoutIntervalForRequest = timeOutFlo
        
        if theManager == nil{
            theManager = TMNetManager.init(configuration: config)
        }

        return theManager!
    }
    
}





/// 网络配置单例类
class Config: URLSessionConfiguration {
    static var theConfig:URLSessionConfiguration?
    class func shareConfig() -> URLSessionConfiguration {
        if theConfig == nil {
            theConfig = URLSessionConfiguration.default
        }
        return theConfig!
    }
}

二、网络请求

//
//  TMNetworkingTool.swift
//  ivygateSwift
//
//  Created by 纪志刚 on 2018/4/24.
//  Copyright © 2018年 纪志刚. All rights reserved.
//

import UIKit
import HandyJSON
import Alamofire
import SwiftyJSON

class TMNetworkingTool: NSObject {
    
    static private var isFirst:Bool = true //是否是第一次点击“确定”按钮
    private static func setHttpHeader() -> HTTPHeaders {
        let Dic = Bundle.main.infoDictionary
//        let buildStr = Dic?["CFBundleVersion"] ?? "" //内部管理版本号
        let versionStr = Dic?["CFBundleShortVersionString"] ?? "" //版本号
        
        //= ["os":"ios","appname":"crm","version":versionStr as! String,"Content-Type":"application/json;charset=UTF-8"]
        var header:HTTPHeaders = HTTPHeaders.init()
        header["os"] = "iOS"
       header["Content-Type"] = "application/json;charset=UTF-8"
        return header
    }
    
    
    
    
     
    
    
    
    
    
    
    /// 网络请求 get/post
    ///
    /// - Parameters:
    ///   - url: 链接
    ///   - method: get/post
    ///   - parameters: 参数列表
    ///   - showLoading: 是否显示loading true显示 false不显示
    ///   - succ: 请求成功 jsonStr:获取结果的json字符串。headerJsonStr:获取的header的json字符串 将返回的所有数据都返回过去,方便以后取responseHeader中的内容
    ///   - fail: 请求失败 errStr:经过处理的错误信息  err:未经整理的错误信息
    static func requestFun(url:String, method:HTTPMethod, parameters:Parameters?,showLoading:Bool = true, succ: @escaping (_ jsonStr: String, _ responseJson: DataResponse<String>) -> Void, fail: @escaping (_ errStr: String,_ err:Error)->()) {
        
    
        
        if showLoading { //显示loading
            TMNetworkingTool.referenceCountChangeFun(isAdd: true)
        }
        var urlStr:String = url
        let header = self.setHttpHeader()
        
        
        let encoding:ParameterEncoding = JSONEncoding.default
        
        
        if method == kHTTPMethodGet {
            let theStr:NSString = NSString.init(string: urlStr)
            urlStr = theStr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
        }
        
        
    TMNetManager.shareManager().request(urlStr, method: method, parameters: parameters, encoding: encoding, headers: header).responseString { (response) in
            
            if showLoading { //显示loading
                TMNetworkingTool.referenceCountChangeFun(isAdd: false)
            }
        
            if response.result.isSuccess { //网络请求成功
                print("header=\(header) \rurlStr=\(urlStr) \rparaDic=\(parameters ?? [:]) \rresponse=\(JSON.init(parseJSON: response.result.value ?? ""))")
                if let value = response.result.value {
                    let json = JSON.init(parseJSON: value)
                    if json["code"].int == 0 {//请求成功
                        succ(value,response)
                    }
                    else{//请求失败,获取err
                        fail(json["message"].string ?? kNetFailMessage, response.error ?? NSError.init())
                    }
                    
                }else{ //没有获取到数据
                    fail(kNetFailMessage, NSError.init())
                }
            }else {//网络请求失败
                fail(kNetFailMessage, NSError.init())
            }
        }
    }
    
    
    
    
    
    
    /// 文件上传
    ///
    /// - Parameters:
    ///   - url: 链接
    ///   - parameters: 参数
    ///   - name: 文件对应key
    ///   - fileName: fileName
    ///   - mimeType: mimeType
    ///   - imgData: 文件流
    ///   - showLoading: 是否显示loading true显示 false不显示
    ///   - succ: <#succ description#>
    ///   - fail: <#fail description#>
    static func uploadFun(url:String,method:HTTPMethod, parameters:Dictionary<String, String>?, name:String, fileName:String ,mimeType:String ,imgData:Data ,showLoading:Bool = true, succ: @escaping (_ jsonStr: String, _ responseJson: DataResponse<String>) -> Void, fail: @escaping (_ errStr: String,_ err:Error)->()) {
        
        let urlStr =  url
        let header = self.setHttpHeader()//请求头
        
        
        TMNetManager.shareManager(timeOutFlo: 60).upload(multipartFormData: { multipartFormData in
            //采用post表单上传
            // 参数解释:
            //withName:和后台服务器的name要一致 ;fileName:可以充分利用写成用户的id,但是格式要写对; mimeType:规定的,要上传其他格式可以自行百度查一下
            multipartFormData.append(imgData, withName: name, fileName: fileName, mimeType: mimeType)
            
            //如果需要上传多个文件,就多添加几个
            //multipartFormData.append(imageData, withName: "file", fileName: "123456.jpg", mimeType: "image/jpeg")
            //......
            
            
            if parameters?.keys != nil && (parameters?.keys.count)! > 0{
                for str in (parameters?.keys)! {
                    let value = parameters![str]
                    multipartFormData.append((value?.data(using: String.Encoding.utf8))!, withName: str)
                }
            }
            
        }, usingThreshold: SessionManager.multipartFormDataEncodingMemoryThreshold, to: urlStr, method: method, headers: header) { encodingResult in
            
            switch encodingResult {
            case .success(let upload, _, _):
                //连接服务器成功后,对json的处理
                
                upload.responseString(completionHandler: { response in

                    
                    if response.result.isSuccess { //网络请求成功
                        print("header=\(header) \rurlStr=\(urlStr) \rparaDic=\(parameters ?? [:]) \rresponse=\(JSON.init(parseJSON: response.result.value ?? ""))")
                        if let value = response.result.value {
                            let json = JSON.init(parseJSON: value)
                            if json["code"].int == 1 || json["code"].int == 0 {//请求成功
                                succ(value,response)
                            }
                            else{//请求失败,获取err
                                fail(json["message"].string ?? kNetFailMessage, response.error ?? NSError.init())
                            }
                            
                        }else{ //没有获取到数据
                            fail(kNetFailMessage, NSError.init())
                        }
                    }else {//网络请求失败
                        fail(kNetFailMessage, NSError.init())
                    }
                    
                })
                //获取上传进度
                upload.uploadProgress(queue: DispatchQueue.global(qos: .utility)) { progress in
                    print("图片上传进度: \(progress.fractionCompleted)")
                }
                break
            case .failure( _):
                fail(kNetFailMessage, NSError.init())
                break
        }
    
    }
    }

    
    /// loading 管理
    ///
    /// - Parameter isAdd: 是否显示loading true引用计数加一 false引用计数减一
    private static func referenceCountChangeFun(isAdd:Bool) {
        if isAdd {
            KNetReferenceCount += 1
            DispatchQueue.main.async {
                TMLoading.shareInstance.show(title: "正在加载")
            }
        }else{
            KNetReferenceCount -= 1
            if KNetReferenceCount <= 0 {
                KNetReferenceCount = 0
                DispatchQueue.main.async {
                    TMLoading.shareInstance.dismissLoading()
                }
            }
        }
    }
    
    
    
    
    

    
    
    /// 网络请求 get/post
    ///
    /// - Parameters:
    ///   - url: 链接
    ///   - method: get/post
    ///   - parameters: 参数列表
    ///   - showLoading: 是否显示loading true显示 false不显示
    ///   - succ: 请求成功 responseModel:获取结果的模型。responseJson获取的所有信息,方便单独获取另外字段
    ///   - fail: 请求失败 errStr:经过处理的错误信息  err:未经整理的错误信息
    public static func request<T:HandyJSON>(t:T.Type,url:String, method:HTTPMethod, parameters:Parameters?,showLoading:Bool = true, succ: @escaping (_ responseModel: T, _ responseJson: DataResponse<String>) -> (), fail: @escaping (_ errStr: String,_ err:Error)->()){
        
    
        
        
        if showLoading { //显示loading
            TMNetworkingTool.referenceCountChangeFun(isAdd: true)
        }
        var urlStr:String = url
        var header = self.setHttpHeader()
        
        
        var encoding:ParameterEncoding = JSONEncoding.default

        
        
        if method == kHTTPMethodGet {
            let theStr:NSString = NSString.init(string: urlStr)
            urlStr = theStr.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
        }
        
        
        TMNetManager.shareManager().request(urlStr, method: method, parameters: parameters, encoding: encoding, headers: header).responseString { (response) in
            
            if showLoading { //显示loading
                TMNetworkingTool.referenceCountChangeFun(isAdd: false)
            }
            
            if response.result.isSuccess { //网络请求成功
                print("header=\(header) \rurlStr=\(urlStr) \rparaDic=\(parameters ?? [:]) \rresponse=\(JSON.init(parseJSON: response.result.value ?? ""))")
                if let value = response.result.value {
                    let json = JSON.init(parseJSON: value)
                    if json["code"].int == 1 {//请求成功
                        
                        print("json[kNet_data_Key]原始值 == \(json["data"])")
                        print("json[kNet_data_Key].dictionaryValue == \(json["data"].dictionaryValue.keys.count)")
                        print("json[kNet_data_Key].arrayValue == \(json["data"].arrayValue.count)")
                        print("json[kNet_data_Key].stringValue == \(json["data"].stringValue.count)")
                        
                        
                        if json["data"].dictionaryValue.keys.count > 0{ //data中是数据是非空字典
                            
                            let responseModel:T = JSONDeserializer<T>.deserializeFrom(json: value, designatedPath: "data") ?? T.init()
                            succ(responseModel,response)
                        }
                        else{//是不确定类型,返回response原始值以备后续操作(空字典、空数组、空字符串等等)
                            succ(T.init(),response)
                        }
                        
                    }
                    else{//请求失败,获取err
                        fail(json["message"].string ?? kNetFailMessage, response.error ?? NSError.init())
                    }
                    
                }else{ //没有获取到数据
                    fail(kNetFailMessage, NSError.init())
                }
            }else {//网络请求失败
                fail(kNetFailMessage, NSError.init())
            }
        }
        
        
    }
    
    
    
    
    
    
}




三、使用

新建model类

//
//  TMMineModel.swift
//  ivygateSwift
//
//  Created by 纪志刚 on 2018/4/24.
//  Copyright © 2018年 纪志刚. All rights reserved.
//

import UIKit
import HandyJSON



class TMMineModel: HandyJSON {
    
    var code:String = ""
    var name:String = ""
    var domain:String = ""
    var captcha:Bool = false
    

    //HandyJSON要求必须实现这个方法
    required init() {
        
    }
    

    /// 获取个人信息
    ///
    /// - Parameters:
    ///   - succ: <#succ description#>
    ///   - fail: <#fail description#>
    static func requestFun(succ: @escaping(_ arr:Array<TMMineModel>) -> (), fail: @escaping (_ errStr: String) -> ()) {
        
        TMNetworkingTool.requestFun(url: "你自己的网络请求", method: kHTTPMethodGet, parameters: nil, showLoading: false, succ: { (responseData, response) in
            succ([TMMineModel].deserialize(from: responseData, designatedPath: "data") as? Array<TMMineModel> ?? Array.init())
        }) { (errStr, err) in
            fail(errStr)
        }
    }
    

}

使用方法

        TMMineModel.requestFun(succ: { (model) in
            print("网络请求成功了")
        }) { (errStr) in
            print("失败了")
        }
image

可以看到网络请求成功之后返回了一个数组,数组内是自定义数据类型

HandyJSON用于数据映射时注意

  1. model类继承自HandyJSON并实现init方法
    //HandyJSON要求必须实现这个方法
    required init(){}

2.重命名属性时实现方法

    func mapping(mapper: HelpingMapper) {
        mapper <<<
            self.ID <-- "id"
        mapper <<<
            self.Description <-- "description"
    }

3.映射为model类和映射为model数组的用法分别为

TMMineSaleStatusModel.deserialize(from: jsonStr, designatedPath: kNet_data_Key) ?? TMMineSaleStatusModel.init()
[TMMineSaleStatusModel].deserialize(from: jsonStr, designatedPath: kNet_data_Key) as? Array<TMMineSaleStatusModel> ?? Array.init()

Demo地址
https://github.com/jizhigang/SwiftNetDemo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335