最近工作不是很忙,表示最近也在一直的學習理論知識,但是光是單純的看書和看面試題崩掘,感覺有點大學期末考試的趕腳吼驶,所以還是想著要把理論和實踐多結合惩激,所以陸續(xù)把工作中的用到的東西整理成一個個Demo 這樣,和盡量的封裝一下子蟹演,這樣也算是平時的一點積累风钻。
首先是覺得可以把網(wǎng)絡的小模塊搞一搞,雖然AFN在ios界是神作酒请,地位不可動搖骡技,但是我們這還是不能單單只會AFN,必備的網(wǎng)絡知識還是要了解羞反,題外話圖解HTTP這本書還是很不錯的布朦,生動形象,簡單易懂的講解了網(wǎng)絡知識昼窗,強烈像我一樣半路出家的人看一看是趴,百度云鏈接。大神請繞行
廢話說了一筐還是直接說代碼吧澄惊,先看一下目錄結構
其實東西很簡單唆途,主要就是實現(xiàn)一個多線程下載的功能,在DownloadManagment 類中有一個字典掸驱,每次調用下載的時候都會建立一個NSURLSessionDownloadTask 下載任務窘哈,然后以URL為Key 把他存到字典中,這樣這樣可以防止重復執(zhí)行下載任務亭敢,而且下載過程中可以暫停任務也就是支持斷點續(xù)傳滚婉,而且可以把執(zhí)行多個任務,還有在任務之間進行切換帅刀。不過之前源代碼實在不敢吐槽让腹,居然把下載的一些緩存啥的都存到了數(shù)據(jù)庫里远剩,感覺好突兀,所以自己改成了存成歸檔文件骇窍,怎么存都可以隨你喜歡啦瓜晤,只不過不喜歡那么搞而已。大概把功能說道這里腹纳,下面就是最激動人心的貼代碼時間痢掠。
首先是DownloadManagment類,負責對外管理類這么搞其實并說不清具體用到了什么設計模式嘲恍,只不過各個牛逼的框架都會這么用足画。
@interface DownloadManagment ()
@property(nonatomic, strong)NSMutableDictionary *downloadDic;//把不同的任務都存到了這個字典里方便管理
@end
@implementation DownloadManagment
+ (instancetype)shareDownloadManagment
{
static DownloadManagment *downloadManagment = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
downloadManagment = [[DownloadManagment alloc]init];
});
return downloadManagment;
}
// 初始化方法
- (instancetype)init
{
self = [super init];
if (self) {
self.downloadDic = [NSMutableDictionary dictionary];
}
return self;
}
// 根據(jù)URL添加一個下載類
- (Download *)addDownloadWithUrl:(NSString *)url
{
// 先從字典里面取到對應的下載
Download *download = self.downloadDic[url];
if (download == nil) {// 如果字典里面沒有 我們就創(chuàng)建一個
download = [[Download alloc]initWithURL:url];
//添加到我們的字典當中
[self.downloadDic setObject:download forKey:url];
}
// 下載完成以后 讓單例不再持有著下載類 從字典里面移除
[download downloadCompleted:^(NSString *url) {
[self.downloadDic removeObjectForKey:url];
NSLog(@"下載完成");
}];
return download;
}
// 根據(jù)URL找到一個下載類
- (Download *)findDownloadWithURL:(NSString *)url
{
return self.downloadDic[url];
}
// 返回所有正在下載的類
- (NSArray *)allDownlod
{
return [self.downloadDic allValues];
}
其次是DownloadingManagment類,不知道原框架為什么會這么起佃牛,這其實就是一個Model累嘛淹辞,叫的人心都醉了。
@interface DownloadingManagment : NSObject<NSCoding>
@property(nonatomic, copy)NSString *resumeDataStr;
@property(nonatomic, copy)NSString *fileSize;
@property(nonatomic, copy)NSString *filePath;
@property(nonatomic, copy)NSString * progress;
@property(nonatomic, copy)NSString *url;
@property(nonatomic, copy)NSString * time;
@property(nonatomic, copy)NSString * DownLoadType;
@end
重頭戲是Download 類俘侠,所有的網(wǎng)絡有關的東西都在這個類里實現(xiàn)
最開始是初始化類
- (id)initWithURL:(NSString *)url
{
self = [super init];
if (self) {
// + (NSURLSessionConfiguration *)defaultSessionConfiguration;
// //返回標準配置象缀,這實際上與NSURLConnection的網(wǎng)絡協(xié)議棧是一樣的,具有相同的共享NSHTTPCookieStorage爷速,共享NSURLCache和共享NSURLCredentialStorage央星。
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
//設置請求超時為10秒鐘
config.timeoutIntervalForRequest = 10;
//在蜂窩網(wǎng)絡情況下是否繼續(xù)請求(上傳或下載)
config.allowsCellularAccess = NO;
self.session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
// 創(chuàng)建任務,把配置的信息惫东,加到任務里莉给,然后開始執(zhí)行
self.task = [_session downloadTaskWithURL:[NSURL URLWithString:url]];
_url = url;
// 先去數(shù)據(jù)庫中查找是否已經(jīng)下載了 如果已經(jīng)下載了 我們就把_isFirst賦值為yes 防止重復添加數(shù)據(jù)
_isFirst =[self findDownloadingWithURL:url];
if (_isFirst) {
// 如果已經(jīng)下載了 我們更換我們的task
self.task = [self.session downloadTaskWithResumeData:[self resumeDataWithURL:url]];
}
}
return self;
}
里面涉及到NSURLSessionConfiguration,具體的可以查看http://www.cnblogs.com/liugengqun/p/5140296.html 博客寫的很詳細 如何配置
接下來斷點續(xù)傳主要功能凿蒜,把下載了的
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSURLSessionDownloadURL</key> //資源的 URL
<string>http://dlhjhx.xicp.net:13081/firmware/E302620170303.pkg</string>
<key>NSURLSessionResumeBytesReceived</key>//錄下來了已經(jīng)下載完成的字節(jié)數(shù)
<integer>68441</integer>
<key>NSURLSessionResumeCurrentRequest</key>//當前請求時的 NSURLRequest 對象
<data>
YnBsaXN0MDDUAQIDBAUGdXZYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS
//省略一萬字
BcMF0AXTBeAF8gX1BhMAAAAAAAACAQAAAAAAAAB5AAAAAAAAAAAAAAAAAAAGFQ==
</data>
<key>NSURLSessionResumeEntityTag</key>
<string>W/"492894-1488511050000"</string>
<key>NSURLSessionResumeInfoTempFileName</key>//下載過程中臨時文件所存儲的位置,存儲在應用程序 tmp 文件夾下
<string>CFNetworkDownload_kv1UKk.tmp</string>
<key>NSURLSessionResumeInfoVersion</key>
<integer>2</integer>
<key>NSURLSessionResumeOriginalRequest</key>//初始請求時的 NSURLRequest 對象
<data>
YnBsaXN0MDDUAQIDBAUGUFFYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3AS
//省略一萬字
BAwEEQQeBCEELgRABEMEYQAAAAAAAAIBAAAAAAAAAFQAAAAAAAAAAAAAAAAAAARj
</data>
<key>NSURLSessionResumeServerDownloadDate</key>
<string>Fri, 03 Mar 2017 03:17:30 GMT</string>
</dict>
</plist>
每次啟動的時候如果遇到未下載完成的任務就會替換任務Data中的已下載的字節(jié)胁黑,然后繼續(xù)添加到任務重繼續(xù)執(zhí)行废封,這樣就可以執(zhí)行斷點續(xù)傳啦
/**
恢復下載替換resumeDataStr 中生于的下載的字節(jié)
@param url url description
@return return value description
*/
- (NSData *)resumeDataWithURL:(NSString *)url
{
// 1.找到下載中的model
DownloadingManagment *downloading = [self findDownloadingWithURL:url];
// 給progress賦初始值
_progress = downloading.progress;
NSLog(@"%@",downloading);
// 2.獲取當前下載的文件
NSFileManager *fm = [NSFileManager defaultManager];
NSString *fileSize = [NSString stringWithFormat:@"%llu", [fm attributesOfItemAtPath:downloading.filePath error:nil].fileSize];
// 3.對resumeDataStr進行替換
downloading.resumeDataStr = [downloading.resumeDataStr stringByReplacingOccurrencesOfString:downloading.fileSize withString:fileSize];
// 4.生成NSData進行返回
return [downloading.resumeDataStr dataUsingEncoding:NSUTF8StringEncoding];
}
最后沒啥可說的了,下載完成后轉移數(shù)據(jù)啥的丧蘸,這玩意關鍵要根據(jù)實際的業(yè)務需求來啦漂洋,剩下的GitHub上有例子,有興趣的童鞋可以下載看一下力喷,我這水平有限刽漂,也就是拋磚引玉,大神請繞行弟孟。GitHub Demo
最后感慨最近體弱多病呀贝咙,藥加起來吃的是我N年的和呀,告誡大家要多強身健體呀拂募,我這體會到身體是革命的本錢庭猩,沒有好身體啥都搞不了窟她,如配圖呀,三月不努力蔼水,四月徒傷悲震糖,五月就沒臉見人啦。要個當一個能撐得起世界的男人