#import "ViewController.h"
#import "ProgressButton.h"
#import "DownloadOperationManager.h"
@interface ViewController ()<NSURLConnectionDataDelegate>
@property (weak, nonatomic) IBOutlet ProgressButton *progressBtn;
@property (nonatomic, strong) NSURL *url;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)pause:(id)sender {
[[DownloadOperationManager shareManager]pause:self.url];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSString *URLStr =@"http://localhost/02文件下载.mp4";
URLStr = [URLStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
self.url = [NSURL URLWithString:URLStr];
[[DownloadOperationManager shareManager]downloadWithUrl:self.url progress:^(CGFloat progress) {
dispatch_async(dispatch_get_main_queue(), ^{
self.progressBtn.progress = progress;
});
} finish:^(NSString *targetPath, NSError *error) {
NSLog(@"下载完成%@ -- %@",targetPath,[NSThread currentThread]);
}];
}
@end
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DownloadOperation : NSOperation
+ (instancetype)downloadWithUrl:(NSURL *)url progress:(void(^)(CGFloat progress))progress finish:(void(^)(NSString *targetPath,NSError *error))finish;
- (void)pause;
@end
#import "DownloadOperation.h"
@interface DownloadOperation ()<NSURLConnectionDataDelegate>
@property (nonatomic, copy) void (^progress)(CGFloat);
@property (nonatomic, copy) void (^finish)(NSString *, NSError *);
@property (nonatomic, assign) long long fileSize;
@property (nonatomic, assign) long long currentLocalSize;
@property (nonatomic, assign) long long currentSize;
@property (nonatomic, strong) NSOutputStream *output;
@property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, copy) NSString *filePath;
@property (nonatomic, strong) NSURL *url;
@end
@implementation DownloadOperation
+ (instancetype)downloadWithUrl:(NSURL *)url progress:(void (^)(CGFloat))progress finish:(void (^)(NSString *, NSError *))finish {
DownloadOperation *download = [[self alloc]init];
download.progress = progress;
download.finish = finish;
download.url = url;
return download;
}
- (void)pause {
[self.connection cancel];
[self.output close];
}
- (void)main {
@autoreleasepool {
[self startDownload];
}
}
- (void)startDownload {
NSURL *url = self.url;
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"HEAD"];
NSHTTPURLResponse *response;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
self.filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
self.fileSize = response.expectedContentLength;
self.currentLocalSize = [self checkLocalFile];
self.currentSize = self.currentLocalSize;
if (self.currentLocalSize == self.fileSize) {
if (self.progress) {
self.progress(1);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (self.finish) {
self.finish(self.filePath,nil);
}
});
return;
}
[self download:url];
}
- (long long)checkLocalFile {
long long fileSize = 0;
NSFileManager *manager = [NSFileManager defaultManager];
NSDictionary *att = [manager attributesOfItemAtPath:self.filePath error:NULL];
long long localFileSize = att.fileSize;
if (localFileSize > self.fileSize) {
[manager removeItemAtPath:self.filePath error:NULL];
fileSize = 0;
}else if (localFileSize == self.fileSize) {
fileSize = localFileSize;
}else {
fileSize = localFileSize;
}
return fileSize;
}
- (void)download:(NSURL *)url {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSString *range = [NSString stringWithFormat:@"bytes=%lld-",self.currentLocalSize];
[request setValue:range forHTTPHeaderField:@"Range"];
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
[[NSRunLoop currentRunLoop] run];
}
#pragma mark - NSURLConnection 代理
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(@"接收到响应%@ -- %lld",response,response.expectedContentLength);
self.output = [[NSOutputStream alloc]initToFileAtPath:self.filePath append:YES];
[self.output open];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
self.currentSize += data.length;
CGFloat progress = (CGFloat)self.currentSize / self.fileSize;
if (self.progress) {
self.progress(progress);
}
[self.output write:data.bytes maxLength:data.length];
[NSThread sleepForTimeInterval:0.1];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"下载完成了");
dispatch_async(dispatch_get_main_queue(), ^{
if (self.finish) {
self.finish(self.filePath,nil);
}
});
[self.output close];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"出错了");
dispatch_async(dispatch_get_main_queue(), ^{
if (self.finish) {
self.finish(nil,error);
}
});
}
- (void)dealloc {
NSLog(@"线程结束");
}
@end
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DownloadOperationManager : NSObject
+ (instancetype)shareManager;
- (void)downloadWithUrl:(NSURL *)url progress:(void(^)(CGFloat progress))progress finish:(void(^)(NSString *targetPath,NSError *error))finish;
- (void)pause:(NSURL *)url;
@end
#import "DownloadOperationManager.h"
#import "DownloadOperation.h"
@interface DownloadOperationManager ()
@property (nonatomic, strong) NSMutableDictionary *operationCache;
@property (nonatomic, strong) NSOperationQueue *queue;
@end
@implementation DownloadOperationManager
+ (instancetype)shareManager {
static dispatch_once_t onceToken;
static DownloadOperationManager *instace;
dispatch_once(&onceToken, ^{
instace = [[self alloc]init];
});
return instace;
}
- (void)downloadWithUrl:(NSURL *)url progress:(void (^)(CGFloat))progress finish:(void (^)(NSString *, NSError *))finished {
if ([self.operationCache objectForKey:url]) {
NSLog(@"正在玩命下载中...请稍等");
return;
}
DownloadOperation *down = [DownloadOperation downloadWithUrl:url progress:progress finish:^(NSString *targetPath, NSError *error) {
NSLog(@"下完完成,移除操作%@",self.operationCache);
[self.operationCache removeObjectForKey:url];
if (finished) {
finished(targetPath,error);
}
}];
[self.operationCache setObject:down forKey:url];
[self.queue addOperation:down];
}
- (void)pause:(NSURL *)url {
DownloadOperation *op = [self.operationCache objectForKey:url];
[op pause];
[self.operationCache removeObjectForKey:url];
}
- (NSOperationQueue *)queue {
if (_queue == nil) {
_queue = [[NSOperationQueue alloc]init];
_queue.maxConcurrentOperationCount = 5;
}
return _queue;
}
- (NSMutableDictionary *)operationCache {
if (_operationCache == nil) {
_operationCache = [NSMutableDictionary dictionary];
}
return _operationCache;
}
@end