对NSURLConnection的简单封装

本文介绍了一个用于iOS应用的文件下载组件实现,通过NSURLConnection进行断点续传,并提供了下载进度反馈及错误处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#import <Foundation/Foundation.h>

@class YGFileDownloader;
@protocol YGFileDownloaderDelegate <NSObject>

-(void)fileDownloader:(YGFileDownloader *)downloader downloadSize:(unsigned long long)downloadSize totalSize:(unsigned long long)totalSize;
-(void)fileDownloaderDidFinishLoad;
-(void)fileDownloaderFailWithError:(NSError *)error;

@end

@interface YGFileDownloader : NSObject

@property (nonatomic,weak) id<YGFileDownloaderDelegate> delegate;

+(instancetype)sharedInstance;
-(void)start:(NSString *)urlStr;
-(void)stop;

@end


#import "YGFileDownloader.h"
#import "NSString+util.h"

@interface YGFileDownloader () <NSURLConnectionDataDelegate>

@property (nonatomic,strong) NSURLConnection *connection;
@property (nonatomic,copy) NSString *downloadDocPath;//这个路径标识我们下载的文件所存储的那个目录,他是写死的,每次下载东西都能放在目录下面
@property (nonatomic,strong) NSFileHandle *fileHandle;
@property (nonatomic) unsigned long long downloadFileSize;//当前下载了多少(字节)
@property (nonatomic) unsigned long long totalFileSize;//文件总大小

@end

@implementation YGFileDownloader

-(NSString *)downloadDocPath{
    if (_downloadDocPath==nil) {
        //找到沙盒的Document目录
        NSString *documentPath=[NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        //上面这句代码和 [NSHomeDirectory()stringByAppendingPathComponent:@"Documents"];一样
        NSString *downloadPath=[documentPath stringByAppendingPathComponent:@"YGFileDownload"];
        BOOL isSuccess=[[NSFileManager defaultManager] createDirectoryAtPath:downloadPath withIntermediateDirectories:YES attributes:nil error:nil];
        if (isSuccess) {
            NSLog(@"创建文件夹成功");
        }
        _downloadDocPath=downloadPath;

    }
    return _downloadDocPath;
}

+(instancetype)sharedInstance{//创建单例对象
    static YGFileDownloader *downloader=nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{//大括号里的代码只会执行一次
        downloader=[[YGFileDownloader alloc] init];
    });
    return downloader;
}

-(void)start:(NSString *)urlStr{
    NSString *fullPath=[self prepareStart:urlStr];
    //获取fullPath标识的文件的大小
    _downloadFileSize=[self readDownloadFileSize:fullPath];
    
    NSMutableURLRequest *request=[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlStr]];
    [request addValue:[NSString stringWithFormat:@"bytes=%llu-",_downloadFileSize] forHTTPHeaderField:@"Range"];//告诉服务器请求_downloadFileSize以后的字节
    self.connection=[[NSURLConnection alloc] initWithRequest:request delegate:self];
    
}
-(NSString *)prepareStart:(NSString *)urlStr{//确保urlStr所对应的沙盒的位置上有文件
    NSString *fileName=urlStr.md5;//把url所对应的MD5值作为文件名
    
    //fullPath代表这个文件具体的位置(路径)
    NSString *fullPath=[self.downloadDocPath stringByAppendingString:fileName];
    
    //如果指定的这个路径下面不存在这个文件,我们就把他创建出来
    BOOL fileExists=[[NSFileManager defaultManager] fileExistsAtPath:fullPath];
    if (!fileExists) {
        [[NSFileManager defaultManager] createFileAtPath:fullPath contents:nil attributes:nil];
    }
    
    //打开这个文件准备往里面写数据
    self.fileHandle=[NSFileHandle fileHandleForWritingAtPath:fullPath];
    
    return fullPath;
    //这个函数的功能是在准备下载文件之前做一些准备工作:1.确保文件存在,2.打开文件准备往里面写数据,3.获取这个文件的确切路径,因为我们在往这个路径所标识的这个文件中写数据(我们下载的数据)
}
-(unsigned long long)readDownloadFileSize:(NSString *)filePath{//读取filePath文件的文件大小
    NSDictionary *fileInfo=[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
    return [fileInfo fileSize];
}


-(void)stop{
    [_connection cancel],_connection=nil;
    [_fileHandle closeFile],_fileHandle=nil;
}

#pragma mark - <NSURLConnectionDataDelegate>
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    _totalFileSize=_downloadFileSize+response.expectedContentLength;
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
    if ([self.delegate conformsToProtocol:@protocol(YGFileDownloaderDelegate)]&&[self.delegate respondsToSelector:@selector(fileDownloaderFailWithError:)]) {
        [self.delegate fileDownloaderFailWithError:error];
    }
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
    if ([self.delegate respondsToSelector:@selector(fileDownloaderDidFinishLoad)]) {
        [self.delegate fileDownloaderDidFinishLoad];
    }
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    [_fileHandle seekToEndOfFile];//设置在末尾追加数据
    [_fileHandle writeData:data];//写入数据
    _downloadFileSize += data.length;
    if ([self.delegate conformsToProtocol:@protocol(YGFileDownloaderDelegate)] && [self.delegate respondsToSelector:@selector(fileDownloader:downloadSize:totalSize:)]) {
        [self.delegate fileDownloader:self downloadSize:_downloadFileSize totalSize:_totalFileSize];
    }
}

@end


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值