? ? ? ?最近遇到問題就是多張圖片上傳服務器該怎么設置.剛開始想到的第一想法就是創(chuàng)建個串行隊列.吧這個串行隊列放在子線程.循環(huán)去上傳.首先,在這里.我們首先模擬一個網(wǎng)絡請求的方法.
#pragma mark -模擬網(wǎng)絡請求-
- (void)GET:(NSString*)url
parameter:(NSDictionary*)parmeter
success:(void(^)(idrespondObject))success
failure:(void(^)(NSError*error))failure{
NSError*error;
if([parmeter[@"id"]isEqualToString:@"0"]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
failure(error);
});
}else{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
success(@"");
});
}
}
一.下來就來寫第一種想到的串行隊列的想法
1.定個全局標示.來記錄上傳的個數(shù)
@property(nonatomic,assign)NSUIntegerindex;
2.分發(fā)任務,請求
//創(chuàng)建一個串行隊列
dispatch_queue_tqueue =dispatch_queue_create("com.xxx.www",NULL);
//分發(fā)任務,放到子線程中
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
dispatch_apply(_images.count, queue, ^(size_tindex) {
[selfGET:@"url"parameter:@{@"youparmater":@"imageStr",@"id": [NSStringstringWithFormat:@"%u",arc4random() %2]}success:^(idrespondObject) {
//記錄
_index++;
}failure:^(NSError*error) {
_index++;
}];
});
});
這樣寫有很大的局限性,不能準確的記錄是哪張上傳失敗,還有想要一張完了再下一張,就像 qq 發(fā)說說有圖片那樣的進度提示,就不好做了.
接下來就說說我們的第二種方法,第二方法用到遞歸算法,主要的思想就是:遞歸需要有邊界條件智蝠、遞歸前進段和遞歸返回段士八。當邊界條件不滿足時售碳,遞歸前進藏否;當邊界條件滿足時搜囱,遞歸返回.這里感謝我的好友顧夢曉,當時是和他討論這個問題時,才想出的這個解決方法.
二.遞歸算法
1.創(chuàng)建幾個全局標識
//圖片數(shù)據(jù)源
@property(nonatomic,strong)NSMutableArray*images;
//標示的下標
@property(nonatomic,assign)NSUIntegerindex;
//第一種失敗回調(diào)所需存儲失敗數(shù)據(jù)
@property(nonatomic,strong)NSMutableArray*faileIndexs;
2.測試調(diào)用的函數(shù)
- (void)test{
_images= [@[[UIImageimageNamed:@"scenery1.jpg"], [UIImageimageNamed:@"scenery2.jpg"], [UIImageimageNamed:@"scenery3.jpg"], [UIImageimageNamed:@"scenery4.jpg"]]mutableCopy];
_faileIndexs= [NSMutableArrayarray];
//上傳圖片
[selfupdateImage:_images[0]completion:^(NSUIntegerindex,BOOLisSuccess) {
//1.失敗回調(diào)1的情況處理
if(isSuccess) {
if(index ==_images.count) {
NSLog(@"上傳完畢,失敗的張數(shù)為:%@",_faileIndexs);
}
NSLog(@"上傳過程第%lu張成功",index);
}else{
if(index ==_images.count) {
NSLog(@"上傳完畢,失敗的張數(shù)為:%@",_faileIndexs);
}
[_faileIndexsaddObject:@(index)];
NSLog(@"上傳過程第%lu張失敗",index);
}
//2.失敗回調(diào)2的情況處理
/*
if (isSuccess) {
if (index == _images.count) {
//上傳所有圖片的成功
NSLog(@"上傳所有的成功");
}
NSLog(@"上傳過程第%lu張成功",index);
}else{
//上傳圖片失敗
NSLog(@"上傳圖片失敗,止于第%lu張",index);
}
*/
}];
}
3.上傳圖片的遞歸算法函數(shù)
- (void)updateImage:(UIImage*)image completion:(void(^)(NSUIntegerindex,BOOLisSuccess))completion{
//壓縮圖片,看自己的要求壓縮比例設置compressionQuality參數(shù),此參數(shù)最好在2-7之間.太小澤壓縮容易失真,太大占用內(nèi)存太大
NSData*dataImage =UIImageJPEGRepresentation(image,1);
//轉(zhuǎn)換的參數(shù)有四個枚舉,分別為:
// NSDataBase64Encoding64CharacterLineLength = 1UL << 0,將最大行長度設置為64個字符,插入你所指定的那一行
// NSDataBase64Encoding76CharacterLineLength = 1UL << 1,將最大行長度設置為76個字符,插入你所指定的那一行
//以下可以控制結(jié)束行數(shù)的:
// NSDataBase64EncodingEndLineWithCarriageReturn = 1UL << 4,設置最大行長度64個字符,并可以指定在哪行結(jié)束
// NSDataBase64EncodingEndLineWithLineFeed = 1UL << 5,指定最大行長度76個字符麸祷,并指定在哪行結(jié)束
//這個轉(zhuǎn)換可以自行g(shù)oogle base64加密
NSString*imageStr = [dataImagebase64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
[selfGET:@"url"parameter:@{@"youparmater": imageStr,@"id": [NSStringstringWithFormat:@"%u",arc4random() %2]}success:^(idrespondObject) {
//如果上傳成功
_index++;
//回調(diào)
completion(_index,YES);
if(_index==_images.count) {
//全部上傳成功
//清空標示
_index=0;
return;
}
//繼續(xù)下一行張
[selfupdateImage:_images[_index]completion:completion];
}failure:^(NSError*error) {
//先判斷是否是最后一張,如果是,則返回
if(_index==_images.count-1) {
completion(_index+1,NO);
//清空標示
_index=0;
return;
}
//失敗,分兩種情況:
//1.跳過失敗的那張,返回失敗信息,繼續(xù)下張上傳
_index++;
completion(_index,NO);
[selfupdateImage:_images[_index]completion:completion];
//2.直接返回,不在進行接下來的上傳工作
/*
completion(_index + 1, NO);
//清空標示
_index = 0;
return ;
*/
}];
}
備注:
1.這里列舉了兩種處理方法:第一種是:只要是失敗了就直接停止在那張就可以了,提示用戶繼續(xù)或者取消,這是根據(jù)回調(diào)的標識下標就可以處理數(shù)據(jù)源來重試或者取消.第二種方法就是:一張失敗后,回調(diào)記錄,接著下張繼續(xù)上傳.在全部操作完成后再提示用戶失敗的圖片.
2.在上傳圖片的遞歸函數(shù)中,在遞歸調(diào)用 block 的時候切記要將第一次傳進來的 blcok 遞歸傳遞給后一個函數(shù),不然下個函數(shù)的 block 就會被替代.成功或者失敗的回調(diào)在圖片張數(shù)大于1時,永遠不會被回調(diào)了.
3.如果要自己修改需求.一定要寫好邊界條件.遞歸在適當?shù)臅r候返回,不然就會成死循環(huán)了.
4.全局的下標標識,在完成后一定要清零,不然在同個界面再次操作的時候,標示還保留的上次的最大值,再次調(diào)用函數(shù),會拋出異常.數(shù)組越界.
三.保留數(shù)據(jù)的做法.
? ? ?這點筆者并沒有寫,就談談思路,就是保留數(shù)據(jù).當用戶點擊了保存后,應該把數(shù)據(jù)保存到數(shù)據(jù)庫,在上傳服務器,這時候就不會讓提示失敗,我們會始終把數(shù)據(jù)上傳到服務器為止.我看在處理藍牙接受到的數(shù)據(jù)就是這樣處理的,應為該數(shù)據(jù)為不保留性,過了就會沒有了,但是用戶要用這塊數(shù)據(jù),不能丟失用戶的數(shù)據(jù),所以我們應該將此數(shù)據(jù)保留到數(shù)據(jù)庫,上傳服務器成功為止.用戶多張圖片感覺也是這樣,應為這幾張圖片是用戶在自己的相冊精挑細選出來的,用戶想的就是要這圖片.不應該就因為一些原因丟失用戶的數(shù)據(jù).喲感興趣的小伙伴可以試試.
今天就寫到這了.周六早晨就下雨,感覺挺舒服清爽的!
補丁:Demo 地址?2016/8/17