自己动手写一个 iOS 网络请求库——封装接口

移动开发 iOS
本篇文章中,我们将一起尝试使用一个类来封装我们之前的代码,并尝试加入动态增加 HTTP 参数(params)的功能,之后封装出一个强大的接口。

代码示例:https://github.com/johnlui/Swift-On-iOS/blob/master/BuildYourHTTPRequestLibrary

开源项目:Pitaya,适合大文件上传的 HTTP 请求库:https://github.com/johnlui/Pitaya

本篇文章中,我们将一起尝试使用一个类来封装我们之前的代码,并尝试加入动态增加 HTTP 参数(params)的功能,之后封装出一个强大的接口。

 

[[135523]]

基本封装

基础准备

新建一个 Swift 空文件,命名为 Network.swift,在里面写一个 Network 类,之后写一个静态方法 request():

class Network{ 
static func request() { 
let session = NSURLSession.sharedSession() 
let request = NSURLRequest(URL: NSURL(string: "http://baidu.com")!) 
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in 
println("just wait for 5 seconds!") 
sleep(5) 
let string = NSString(data: data, encoding: NSUTF8StringEncoding) 
println(string) 
}) 
task.resume() 


  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

修改 ViewController 中的按钮函数:

@IBAction func mainButtonBeTapped(sender: AnyObject) { 
Network.request() 

  • 1.
  • 2.
  • 3.

运行项目,点击按钮,效果和之前一致。

自定义 HTTP method 和 URL

修改 request() 方法,将 HTTP 方法和 URL 传进去:

static func request(method: String, url: String) { 
let session = NSURLSession.sharedSession() 
let request = NSMutableURLRequest(URL: NSURL(string: url)!) 
request.HTTPMethod = method 
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in 
println("just wait for 5 seconds!"
sleep(5
let string = NSString(data: data, encoding: NSUTF8StringEncoding) 
println(string) 
}) 
task.resume() 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

修改前面的函数调用:

@IBAction func mainButtonBeTapped(sender: AnyObject) { 
Network.request("GET", url: "http://baidu.com"

  • 1.
  • 2.
  • 3.

运行项目,点击按钮,效果和之前一致。

使用闭包处理请求结果

函数是 Swift 中的一等公民,闭包可以作为函数参数和返回值,十分强大。下面我们就用闭包来处理网络请求的返回值。修改 request() 方法,传递进去一个闭包:

static func request(method: String, url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
let session = NSURLSession.sharedSession() 
let request = NSMutableURLRequest(URL: NSURL(string: url)!) 
request.HTTPMethod = method 
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in 
callback(data: data, response: response , error: error) 
}) 
task.resume() 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

在前面函数调用处使用闭包进行结果处理:
 

@IBAction func mainButtonBeTapped(sender: AnyObject) { 
Network.request("GET", url: "http://baidu.com") { (data, response, error) -> Void in 
println("just wait for 5 seconds!"
sleep(5
let string = NSString(data: data, encoding: NSUTF8StringEncoding) 
println(string) 


  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

运行项目,点击按钮,效果和之前一致。

动态增加 Params

GET 方法

GET 方法下,params 在经过 url encode 之后直接附在 URL 末尾发送给服务器。修改 request() 方法,传递进去一个 params 的字典:

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

  • 1.
  • 2.
  • 3.

为了处理 params,我们从 Alamofire 偷来他的 params 处理函数。如果是 GET 方法,那就把处理过的 params 增加到 URL 后面。Network 类的完整代码如下:
 

class Network{ 
static func request(method: String, url: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
let session = NSURLSession.sharedSession() 
 
var newURL = url 
if method == "GET" { 
newURL += "?" + Network().buildParams(params) 

 
let request = NSMutableURLRequest(URL: NSURL(string: newURL)!) 
request.HTTPMethod = method 
 
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in 
callback(data: data, response: response , error: error) 
}) 
task.resume() 

 
// 从 Alamofire 偷了三个函数 
func buildParams(parameters: [String: AnyObject]) -> String { 
var components: [(String, String)] = [] 
for key in sorted(Array(parameters.keys), [(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.extend([(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 


  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.

修改前面的函数调用:

@IBAction func mainButtonBeTapped(sender: AnyObject) { 
Network.request("GET", url: "http://pitayaswift.sinaapp.com/pitaya.php", params: ["get""Network"]) { (data, response, error) -> Void in 
let string = NSString(data: data, encoding: NSUTF8StringEncoding) 
println(string) 


  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

http://pitayaswift.sinaapp.com/pitaya.php 是我部署的用于测试的服务端代码,会直接返回 ?get=ooxx 中的 ooxx。运行项目,点击按钮,查看效果:

POST 方法

POST 方法下有几个协议可供选择,此处没有文件上传,我们采用较简单的 application/x-www-form-urlencoded 方式发送请求。request() 方法增加一些代码:

static func request(method: String, url: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
let session = NSURLSession.sharedSession() 
 
var newURL = url 
if method == "GET" { 
newURL += "?" + Network().buildParams(params) 

 
let request = NSMutableURLRequest(URL: NSURL(string: newURL)!) 
request.HTTPMethod = method 
 
if method == "POST" { 
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type"
request.HTTPBody = Network().buildParams(params).dataUsingEncoding(NSUTF8StringEncoding) 

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

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

修改前面的函数调用:

@IBAction func mainButtonBeTapped(sender: AnyObject) { 
Network.request("POST", url: "http://pitayaswift.sinaapp.com/pitaya.php", params: ["post""Network"]) { (data, response, error) -> Void in 
let string = NSString(data: data, encoding: NSUTF8StringEncoding) 
println(string) 


  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

使用 POST 方式发送请求,同样服务端会返回 key 为 post 的 value 的值。运行项目,点击按钮,结果和前面 GET 方法的结果一致。

至此,接口封装完成!

责任编辑:chenqingxiang 来源: 吕文翰_JohnLui 的博客
相关推荐

2015-06-02 10:24:43

iOS网络请求降低耦合

2015-06-02 09:41:00

iOS网络请求NSURLSessio

2017-03-02 13:31:02

监控系统

2023-12-16 13:21:00

Python元类ORM

2024-12-06 09:58:09

2020-09-29 12:13:46

SQL引擎底层

2017-02-14 10:20:43

Java Class解析器

2015-07-23 14:53:50

贝叶斯分类器

2014-11-26 10:54:20

C#

2023-12-15 10:14:42

数据库select语句

2021-02-22 17:17:38

Proxy缓存代码

2021-07-04 10:07:04

Virtual DO阅读源码虚拟DOM

2018-04-08 11:20:43

深度学习

2024-03-08 12:45:00

C#Web服务器

2018-02-07 10:46:20

数据存储

2018-09-12 10:58:11

NBA数据存储

2021-04-26 07:31:22

SpringMVCweb框架

2022-08-29 14:22:03

bpmn.jsVue流程

2012-07-30 09:40:52

Lua

2022-03-09 09:43:01

工具类线程项目
点赞
收藏

51CTO技术栈公众号