使用NSURLConnection下载
蛋疼的是,一个213M的文件内存峰值能到173M....
参考了这两个文章:http://blog.csdn.net/fightper/article/details/20036203
http://blog.csdn.net/lengshengren/article/details/12905697/
//
// ViewController.swift
// 下载
//
// Created by zhang on 16/2/28.
// Copyright © 2016年 jin. All rights reserved.
//
/**
NSURLConnection存在的问题,iOS2.0就有了。 专门用来负责网络数据的传输,已经有10多年的历史
特点:
- 处理简单的网络操作,非常简单
- 但是处理复杂的网络操作,就非常繁琐
ASI&AFN
iOS 5.0以前,网络的下载是一个黑暗的时代
*** iOS5.0以前 通过代理的方式来处理网络数据
存在的问题:
1.下载的过程中,没有”进度的跟进“ -- 用户的体验不好
2.存在内存的峰值
解决进度跟进的问题
解决办法:通过代理的方式来处理网络数据
代理还是出现峰值, 是因为全部接受完了,再去写入
解决办法,接收到一点,写一点
// NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(click) userInfo:nil repeats:YES];
//// NSDefaultRunLoopMode : 默认的运行循环模式。 处理的优先级比NSRunLoopCommonModes低
//// NSRunLoopCommonModes : 通用的模式,在用户拖动屏幕的时候同样执行
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
NSURLConnection的代理,默认是在主线程运行的
需要把他的代理 移到子线程执行
下载这个任务 本身还在主线程。 所有导致进度条的更新非常卡
主线程现在在做两件事,1. 下载 2.更新进度条
NSURLConnection问题:
1. 做复杂的网络操作,需要使用代理来实现。 比如下载大文件
2. 默认下载任务在主线程工作。
3. 默认这个任务的代理也是在主线程
4. 如果添加到子线程去执行,需要主动启动运行循环
5. 只提供开始和取消。 不支持暂停。
*/
import UIKit
class ViewController: UIViewController,NSURLConnectionDataDelegate {
@IBOutlet weak var progress: UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/**
这样执行的话,是在主线程执行的
let connection = NSURLConnection(request: request, delegate: self ,startImmediately: false)
connection?.scheduleInRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
connection?.start()
*/
// 把网络请求放到子线程
NSOperationQueue().addOperationWithBlock { () -> Void in
let url = NSURL(string: "http://localhost/1.mp4")
let request = NSMutableURLRequest(URL: url!, cachePolicy: NSURLRequestCachePolicy.ReloadIgnoringCacheData, timeoutInterval: 10)
// 这个文件比较大
let queue = NSOperationQueue()
queue.maxConcurrentOperationCount = 1
let connection = NSURLConnection(request: request, delegate: self ,startImmediately: false)
// 设置代理执行的线程在子进程
connection?.setDelegateQueue(queue)
// 开始
connection?.start()
}
}
var fileSize:Int64 = 0
var currentSize:Int64 = 0
// 接受请求
func connection(connection: NSURLConnection, didReceiveResponse response: NSURLResponse) {
/**
response里面的信息
{ URL: http://localhost/1.mp4 } { status code: 200, headers {
"Accept-Ranges" = bytes;
Connection = "Keep-Alive";
"Content-Length" = 213811516;
Date = "Sun, 28 Feb 2016 02:22:25 GMT";
Etag = "\"cbe813c-528c686a2b8c0\"";
"Keep-Alive" = "timeout=5, max=100";
"Last-Modified" = "Thu, 07 Jan 2016 23:06:51 GMT";
Server = "Apache/2.4.18 (Unix) OpenSSL/1.0.2f PHP/7.0.2 mod_perl/2.0.8-dev Perl/v5.16.3";
} }
*/
// 获得文件的总长度
self.fileSize = response.expectedContentLength
self.currentSize = 0
// 避免重复写入的问题
try? NSFileManager.defaultManager().removeItemAtPath(self.path)
}
// 定义保存文件的路径
let path = "/Users/zhang/Desktop/123.mp4"
// 接受数据
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
// 获得文件资源文件句柄
let handle = NSFileHandle(forWritingAtPath: path)
// 文件不存在的时候使用nsdata进行写入
if handle == nil
{
data.writeToFile(path, atomically: true)
}
else
{
// 移动指向到文件尾部,避免每次写入都吧文件替换了
handle?.seekToEndOfFile()
// 写入
handle?.writeData(data)
}
// 一定要关闭!!!
handle?.closeFile()
// 当前已经下载的文件的大小,去主线程更新ui
NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in
self.currentSize += data.length
self.progress.progress = Float(Float64(self.currentSize) / Float64(self.fileSize))
}
}
func connectionDidFinishLoading(connection: NSURLConnection) {
print("连接完成")
}
func connection(connection: NSURLConnection, didFailWithError error: NSError) {
print("错误啦")
}
}