码迷,mamicode.com
首页 > 编程语言 > 详细

swift 动手写网络请求封装(仿照了一个大神的)不用导入第三方

时间:2016-08-11 15:56:23      阅读:273      评论:0      收藏:0      [点我收藏+]

标签:

新建一个类Network

import UIKit

 

//NSURLSession 的使用过程:

//

//构造 NSURLRequest

//确定 URL

//确定 HTTP 方法(GETPOST 等)

//添加特定的 HTTP

//填充 HTTP Body

//驱动 session.dataTaskWithRequest 方法,开始请求

 

 

//(5)设置 SSL 证书钢钉。在我们调用 HTTPS 协议的时候,事先把 SSL 证书存到 App 本地,然后在每次请求的时候都进行一次验证,避免中间人攻击(Man-in-the-middle attack)。同时,这个功能也是我们使用自签名证书时候必须的,因为系统默认会拒绝我们自己签名的不受信任的证书,导致连接失败。

 

// MARK: 提供的各种调用接口:GET,POST,文件上传

class Network: NSObject{

    

    // 不带参数的get请求

    /*

  

     请求方法的URL    url: get

 

     callback闭包   data: 请求成功的数据,

                     response: 拿到数据的解析回应,

                    error: 请求错误]

     NetworkManager()  一个初始化URLparamshttpfiles文件的类

     fire()        使用一个统一的方法来驱动上面三个 function(),完成请求:

     

     

     */

    static func get(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        let manager = NetworkManager(url: url, method: "GET", callback: callback)

        manager.fire()

    }

    // 带参数的get请求

    /*

     

     请求方法的URL    url: get

     请求参数        paramsdictionary

     callback闭包   data: 请求成功的数据,

                    response: 拿到数据的解析回应,

                    error: 请求错误]

     NetworkManager()  一个初始化URLparamshttpfiles文件的类

     fire()        使用一个统一的方法来驱动上面三个 function(),完成请求:

     

     

     */

    static func get(url: String, params: Dictionary<String, AnyObject>, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        let manager = NetworkManager(url: url, method: "GET", params: params, callback: callback)

        manager.fire()

    }

    // 不带参数的post请求

    /*

     

     请求方法的URL    url: post

     

     callback闭包   data: 请求成功的数据,

                     response: 拿到数据的解析回应,

                      error: 请求错误]

     NetworkManager()  一个初始化URLparamshttpfiles文件的类

     fire()        使用一个统一的方法来驱动上面三个 function(),完成请求:

     

     

     */

    static func post(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        let manager = NetworkManager(url: url, method: "POST", callback: callback)

        manager.fire()

    }

    // 带参数的post请求

    /*

     

     请求方法的URL    url: post

     请求参数         paramsdictionary

     callback闭包   data: 请求成功的数据,

                    response: 拿到数据的解析回应,

                      error: 请求错误]

     NetworkManager()  一个初始化URLparamshttpfiles文件的类

     fire()        使用一个统一的方法来驱动上面三个 function(),完成请求:

     

     

     */

    static func post(url: String, params: Dictionary<String, AnyObject>, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        let manager = NetworkManager(url: url, method: "POST", params: params, callback: callback)

        manager.fire()

    }

    

    

    //MARK: 不带 params files 的接口

    /*

     

     提供请求方法类型  method: String

     请求方法的URL    url: String

 

     callback闭包   data: 请求成功的数据,

                      response: 拿到数据的解析回应,

                    error: 请求错误]

     NetworkManager()  一个初始化URLparamshttpfiles文件的类

     fire()        使用一个统一的方法来驱动上面三个 function(),完成请求:

     

     

     */

    static func request(method: String, url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        let manager = NetworkManager(url: url, method: method, callback: callback)

        manager.fire()

    }

    

    //MARK: 带参数不带files

    /*

     

     提供请求方法类型  method: String

       请求方法的URL    url: String

       请求方法的参数  params: Dictionary

       callback闭包   data: 请求成功的数据,

                       response: 拿到数据的解析回应,

                        error: 请求错误]

      NetworkManager()  一个初始化URLparamshttpfiles文件的类

     fire()        使用一个统一的方法来驱动上面三个 function(),完成请求:

   

 

     */

    static func request(method: String, url: String, params: Dictionary<String, AnyObject>, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        let manager = NetworkManager(url: url, method: method, params: params, callback: callback)

        manager.fire()

    }

    

    //MARK:不带参数带files

    /*

     

     提供请求方法类型  method: String

     请求方法的URL    url: String

      请求文件        filesarray

     callback闭包   data: 请求成功的数据,

                     response: 拿到数据的解析回应,

                        error: 请求错误]

     NetworkManager()  一个初始化URLparamshttpfiles文件的类

     fire()        使用一个统一的方法来驱动上面三个 function(),完成请求:

     

     

     */

    static func request(method: String, url: String, files: Array<File>, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        let manager = NetworkManager(url: url, method: method, files: files, callback: callback)

        manager.fire()

    }

    

     //MARK: 参数和files 的接口

    /*

     

     提供请求方法类型  method: String

     请求方法的URL    url: String

     请求方法的参数  params: Dictionary

     请求文件        filesarray

     callback闭包   data: 请求成功的数据,

                     response: 拿到数据的解析回应,

                     error: 请求错误]

     NetworkManager()  一个初始化URLparamshttpfiles文件的类

     fire()        使用一个统一的方法来驱动上面三个 function(),完成请求:

     

     

     */

    

    static func request(method: String, url: String, params: Dictionary<String, AnyObject>, files: Array<File>, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        let manager = NetworkManager(url: url, method: method, params: params, files: files, callback: callback)

        manager.fire()

    }

}

 

// MARK: - nsdata属性是string的扩展

extension String {

    var nsdata: NSData {

        return self.dataUsingEncoding(NSUTF8StringEncoding)!

    }

}

 

// MARK: 定义的文件格式

struct File {

    let name: String!

    let url: NSURL!

    init(name: String, url: NSURL) {

        self.name = name

        self.url = url

    }

}

 

// MARK: - 新建一个 NetworkManager 类,将 URLparamsfiles 等设为成员变量,让他们在构造函数中初始化:

class NetworkManager: NSObject, NSURLSessionDelegate { //证书实现NSURLSessionDelegate的协议

    //todo  boundary 是我们自己指定的文件间隔符。

    let boundary = "PitayaUGl0YXlh"

    

    let method: String!

    let params: Dictionary<String, AnyObject>

    let callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void

    

     // add files

    var files: Array<File>

    

    var session: NSURLSession!

    let url: String!

    var request: NSMutableURLRequest!

    var task: NSURLSessionTask!

    

    //ssl  增加两个成员变量实现ssl证书检查代理方法干预网络请求

    var localCertData: NSData!

    var sSLValidateErrorCallBack: (() -> Void)?

    

     // add files

    init(url: String, method: String, params: Dictionary<String, AnyObject> = Dictionary<String, AnyObject>(), files: Array<File> = Array<File>(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {

        self.url = url

        self.request = NSMutableURLRequest(URL: NSURL(string: url)!)

        self.method = method

        self.params = params

        self.callback = callback

         // add files

        self.files = files

        

        super.init()

        //ssl 自定义nsurlsession对象

        self.session = NSURLSession(configuration: NSURLSession.sharedSession().configuration, delegate: self, delegateQueue: NSURLSession.sharedSession().delegateQueue)

    }

    //ssl  增加设置ssl函数

    func addSSLPinning(LocalCertData data: NSData, SSLValidateErrorCallBack: (()->Void)? = nil) {

        self.localCertData = data

        self.sSLValidateErrorCallBack = SSLValidateErrorCallBack

    }

    //ssl 实现证书代理方法,介入网络请求

    @objc func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {

        if let localCertificateData = self.localCertData {

            if let serverTrust = challenge.protectionSpace.serverTrust,

                certificate = SecTrustGetCertificateAtIndex(serverTrust, 0),

                remoteCertificateData: NSData = SecCertificateCopyData(certificate) {

                if localCertificateData.isEqualToData(remoteCertificateData) {

                    let credential = NSURLCredential(forTrust: serverTrust)

                    challenge.sender?.useCredential(credential, forAuthenticationChallenge: challenge)

                    completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, credential)

                } else {

                    challenge.sender?.cancelAuthenticationChallenge(challenge)

                    completionHandler(NSURLSessionAuthChallengeDisposition.CancelAuthenticationChallenge, nil)

                    self.sSLValidateErrorCallBack?()

                }

            } else {

                NSLog("Get RemoteCertificateData or LocalCertificateData error!")

            }

        } else {

            completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, nil)

        }

    }

    

     //MARK: 使用一个统一的方法来驱动上面三个 function,完成请求:

    func fire() {

        buildRequest()

        buildBody()

        fireTask()

    }

    //MARK: 确定URLhttp方法、添加特定的http

    func buildRequest() {

        if self.method == "GET" && self.params.count > 0 {

            self.request = NSMutableURLRequest(URL: NSURL(string: url + "?" + buildParams(self.params))!)

        }

        

        request.HTTPMethod = self.method

        

        //   Content-Type

        if self.files.count > 0 {

            request.addValue("multipart/form-data; boundary=" + self.boundary, forHTTPHeaderField: "Content-Type")

        } else if self.params.count > 0 {

            request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

        }

    }

      //MARK:  填充 HTTP Body

    func buildBody() {

        let data = NSMutableData()

        if self.files.count > 0 {

            if self.method == "GET" {

                NSLog("\n\n------------------------\nThe remote server may not accept GET method with HTTP body. But Pitaya will send it anyway.\n------------------------\n\n")

            }

            for (key, value) in self.params {

                data.appendData("--\(self.boundary)\r\n".nsdata)

                data.appendData("Content-Disposition: form-data; name=\"\(key)\"\r\n\r\n".nsdata)

                data.appendData("\(value.description)\r\n".nsdata)

            }

            for file in self.files {

                data.appendData("--\(self.boundary)\r\n".nsdata)

                data.appendData("Content-Disposition: form-data; name=\"\(file.name)\"; filename=\"\(NSString(string: file.url.description).lastPathComponent)\"\r\n\r\n".nsdata)

                if let a = NSData(contentsOfURL: file.url) {

                    data.appendData(a)

                    data.appendData("\r\n".nsdata)

                }

            }

            data.appendData("--\(self.boundary)--\r\n".nsdata)

        } else if self.params.count > 0 && self.method != "GET" {

            data.appendData(buildParams(self.params).nsdata)

        }

        request.HTTPBody = data

    }

    //MARK:  将请求任务执行

    func fireTask() {

        task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in

            self.callback(data: data, response: response, error: error)

        })

        task.resume()

    }

    // MARK: Alamofire 偷了三个函数

    func buildParams(parameters: [String: AnyObject]) -> String {

        var components: [(String, String)] = []

        for key in Array(parameters.keys).sort(<) {

            let value: AnyObject! = parameters[key]

            components += self.queryComponents(key, value)

        }

        

        return (components.map{"\($0)=\($1)"} as [String]).joinWithSeparator("&")

    }

    func queryComponents(key: String, _ value: AnyObject) -> [(String, String)] {

        var components: [(String, String)] = []

        if let dictionary = value as? [String: AnyObject] {

            for (nestedKey, value) in dictionary {

                components += queryComponents("\(key)[\(nestedKey)]", value)

            }

        } else if let array = value as? [AnyObject] {

            for value in array {

                components += queryComponents("\(key)", value)

            }

        } else {

            components.appendContentsOf([(escape(key), escape("\(value)"))])

        }

        

        return components

    }

    func escape(string: String) -> String {

        let legalURLCharactersToBeEscaped: CFStringRef = ":&=;+!@#$()‘,*"

        return CFURLCreateStringByAddingPercentEscapes(nil, string, nil, legalURLCharactersToBeEscaped, CFStringBuiltInEncodings.UTF8.rawValue) as String

    }

}

 

主界面测试:

import UIKit

 

class ViewController: UIViewController {

 

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

        

        

        let mainBtn = UIButton.init(frame: CGRectMake(200, 200, 100, 50))

        mainBtn.backgroundColor = UIColor.redColor()

        mainBtn.addTarget(self, action: #selector(mainBtnBeTapped), forControlEvents: .TouchUpInside)

        self.view.addSubview(mainBtn)

    }

    

    func mainBtnBeTapped(sender:AnyObject) {

        let url = "http://pitayaswift.sinaapp.com/pitaya.php"

        

        Network.post(url, callback: { (data, response, error) -> Void in

            print("POST 1 请求成功")

        })

        Network.post(url, params: ["post": "POST Network"], callback: { (data, response, error) -> Void in

            let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String

            print("POST 2 请求成功 " + string)

        })

        

        Network.get(url, callback: { (data, response, error) -> Void in

            print("GET 1 请求成功")

        })

        Network.get(url, params: ["get": "POST Network"], callback: { (data, response, error) -> Void in

            let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String

            print("GET 2 请求成功 " + string)

        })

        

        Network.request("GET", url: url, params: ["get": "Request Network"]) { (data, response, error) -> Void in

            let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String

            print("Request 请求成功 " + string)

        }

 

}

 

}

来一张测试图:

技术分享

 

swift 动手写网络请求封装(仿照了一个大神的)不用导入第三方

标签:

原文地址:http://www.cnblogs.com/linxiu-0925/p/5761040.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!