本文是我学习 iOS 网络编程整理的笔记,目的在于以后需要用到时可以直接有代码示例帮我解决问题。
还在不断完善当中。
欢迎朋友们纠错。
基本网络数据获取
分三步走:建立URL,获取数据,使用数据。
// 1. 建立地址URL,这里是在苹果官网上随便找了个图片。
// 2. 获取地址的Data数据,当然也可以是NSString或者其他格式的数据,但是这里是图片。因此获取下来是NSData数据。
// 3. 使用数据,这里直接用data建立UIImage并使用它。只是掩饰个用法,具体根据业务需求。
let url = NSURL(string:
let data = NSData(contentsOfURL: url)
self.imageView.image = UIImage(data: data!)
当然实际操作中并不会像上面这样来获取数据,因为这样做会直接在主线程当中进行网络获取,从而导致线程被堵塞。因此需要加入异步处理。
// 1. 建立地址URL
let url = NSURL(string:
// 2. 调用异步线程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// 3. 在异步线程中进行网络请求
let data = NSData(contentsOfURL: url)
// 4. 返回主线程(如果不设置UI操作,其实也可以不返回,要根据实际业务决定。)
dispatch_async(dispatch_get_main_queue()) {
// 5. 对获取的数据进行操作。
self.imageView.image = UIImage(data: data!)
})
}
</br>
NSURLSession
基础知识
基本使用步骤:
- 建立 URL 地址。
- 建立 Request 请求。
- 获取或生成 NSURLSession。
- 建立 NSURLSessionTask 任务。
- 开始下载并接收数据。
NSURLSessionTask 类型
这里写图片描述NSURLSessionTask 常用操作
var state: NSURLSessionTaskState { get } // 当前状态
cancel() // 取消
resume() // 恢复
suspend() // 暂停
Get请求示例
// 1. 建立URL
let url = NSURL(string:
// 2. 建立Request
let request = NSURLRequest(URL: url)
// 3. 获取系统提供的Session
let session = NSURLSession.sharedSession()
// 4. 建立Task
/* Block中提供的三个参数分别是
元数据;
响应信息(如果是 HTTP 或 HTTPS 的话,这其实是一个NSHTTPURLResponse 对象。);
错误信息。*/
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
// 5. 类型转换
let httpResponse = response as! NSHTTPURLResponse
// 6. 判断是否请求正确
if httpResponse.statusCode == 200 {
// 7. 进行数据处理。如果涉及到UI,需要回调主线程。这里用webView加载获取到的HTML数据。
dispatch_async(dispatch_get_main_queue()) {
let htmlString = String(data: data!, encoding: NSUTF8StringEncoding)
let webView = UIWebView(frame: self.view.frame)
webView.loadHTMLString(htmlString!, baseURL: nil)
self.view.addSubview(webView)
}
}
})
// 8. 启动任务
task.resume()
POST请求示例
let url = NSURL(string:
// 与 Get 的不同点,使用 NSMutableURLRequest 并根据具体任务设置其属性。
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = "username=xxxx&pwd=xxxx".dataUsingEncoding(NSStringEncoding.min)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
if httpResponse.statusCode == 200 {
// ...
}
})
task.resume()
NSURLSessionDataDelegate 小文件下载示例
// ------- 配置部分 ------
let url = NSURL(string:
// Get
let request = NSURLRequest(URL: url)
/* Post
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = "username=xxxx&pwd=xxxx".dataUsingEncoding(NSStringEncoding.min)
*/
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
// 设置超时时长
configuration.timeoutIntervalForRequest = 10
// 设置是否允许使用窝蜂网络
configuration.allowsCellularAccess = false
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue())
let task = session.dataTaskWithRequest(requsst)
task.resume()
// MARK: - NSURLSessionDataDelegate 常用方法
// 1. 接收到服务器的响应,必须给 completionHandler 传值,才能根据你传递的值继续下一步操作。
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
let httpResponse = response as! NSHTTPURLResponse
switch httpResponse.statusCode {
case 200 ..< 300:
// 作业继续正常进行
completionHandler(NSURLSessionResponseDisposition.Allow)
case 500 ..< 700:
// 作业取消
completionHandler(NSURLSessionResponseDisposition.Cancel)
default:
// 代理会调用 URLSession:dataTask:didBecomeDownloadTask: 方法让你开始一个下载作业来代替当前通讯作业。
completionHandler(NSURLSessionResponseDisposition.BecomeDownload)
}
}
// 1.* 当在 URLSession:dataTask:DidReceiveResponse:completionHandler: 方法中传入 NSURLSessionResponseDisposition.BecomeDownload 时会调用此代理。用于重置下载作业。
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask) {
}
// 2. 每次接收到服务器的数据就会调用并返回数据。(将多次被调用)
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
// 此处的 data 每次只会返回当前接收到的数据。之前已经发送的数据就不会重复发送,因此需要另外设置变量整合数据。
// 由于 NSData 对象往往是由许多不同的对象组合而成,因此最好使用 NSData 的 enumerateByteRangesUsingBlock: 来遍历数据。
}
// 3. 请求完成。如果失败的话,error有值。
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
}
NSURLSessionDownloadDelegate 大文件下载示例(不支持断点续传)
// ------- 配置部分 ------
let url = NSURL(string:
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = "username=xxxx&pwd=xxxx".dataUsingEncoding(NSStringEncoding.min)
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.timeoutIntervalForRequest = 10
configuration.allowsCellularAccess = false
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue())
let task = session.downloadTaskWithRequest(request)
task.resume()
// MARK: - NSURLSessionDownloadDelegate 常用方法
// 1. 已经恢复下载。
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
}
// 2. 每次写入数据到临时文件就会调用此方法。totalBytesExpectedToWrite 总大小。totalBytesWritten 总共写入多少。bytesWritten 本次写入多少。
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
}
// 3. 下载完毕会调用此方法。
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
// 把下载好的零食文件放置到新文件当中。
let newFilePath = NSHomeDirectory()
try! NSFileManager.defaultManager().moveItemAtURL(location, toURL: NSURL(string: newFilePath)!)
}
// 4. 下载完成
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
}
NSURLSessionDownloadDelegate 大文件下载示例(支持断点传送)
由于GitHub不支持断点传送,所以这段代码未验证其正确性。
基本思路如下:
- 计算已经下载的文件大小。并通过配置 NSMutableRequest 来下载后续部分。
- 配置 NSURLSessionDataTask。
- 配置NSOutputStream 在每次下载到数据后就立即保存到本地。
- 下载完成后,将文件从临时路径转移到目标路径。
import UIKit
class ViewController: UIViewController, NSURLSessionDataDelegate {
@IBAction func start(sender: AnyObject) {
fileName: "myron.zip")
}
@IBAction func stop(sender: AnyObject) {
task.suspend()
task.cancel()
}
override func viewDidLoad() {
super.viewDidLoad()
print(NSHomeDirectory())
}
var url: NSURL!
var request: NSMutableURLRequest!
var configuration: NSURLSessionConfiguration!
var session: NSURLSession!
var task: NSURLSessionDataTask!
var filePath: String!
var fileData: NSMutableData!
var stream: NSOutputStream!
var tmpPath: String!
func createDownloadTask(urlString: String, fileName: String) {
filePath = "\(NSHomeDirectory())/Library/Caches/\(fileName)"
tmpPath = "\(NSHomeDirectory())/tmp/\(fileName)"
stream = NSOutputStream(toFileAtPath: tmpPath, append: true)
// 下载地址
url = NSURL(string: urlString)!
request = NSMutableURLRequest(URL: url)
if let fileAttributes = try? NSFileManager.defaultManager().attributesOfItemAtPath(tmpPath) {
let size = fileAttributes[NSFileSize]!.integerValue
print(size)
request.setValue("bytes=\(size)-", forHTTPHeaderField: "Range")
}
configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue())
task = session.dataTaskWithRequest(request)
print("start")
task.resume()
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
if let httpResponse = response as? NSHTTPURLResponse {
if httpResponse.statusCode == 200 {
print("didReceiveResponse - Allow")
stream.open()
print(httpResponse.allHeaderFields["Content-Length"]?.integerValue)
completionHandler(NSURLSessionResponseDisposition.Allow)
return
}
}
print("didReceiveResponse - Cancel")
completionHandler(NSURLSessionResponseDisposition.Cancel)
}
func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
stream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)
print("didReceiveData")
}
func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
if error == nil {
print("didCompleteWithError - Ok")
stream.close()
stream = nil
do {
try NSFileManager.defaultManager().moveItemAtPath(tmpPath, toPath: filePath)
} catch {
print("File Move Error")
}
}
print("didCompleteWithError - Error")
}
}
</br>
HTTP 响应码
1字头:消息
2字头:成功
3字头:重定向
4字头:请求错误
5、6字头:服务器错误
</br>
错误处理
解决方法:在Info.plist中加入关键字
这里写图片描述NSAppTransportSecurity
字典,以及它的NSAllowsArbitraryLoads
关键字,选择YES
.
具体显示为: