項(xiàng)目需求:允許用戶可以選擇多張圖片上傳到服務(wù)器(使用的七牛云).
思路:
- 一開始想的是任務(wù)分發(fā),將所有圖片遍歷放到子線程中上傳,這樣N張圖片會(huì)同時(shí)上傳。但這樣有弊端:如果需要精確顯示上傳進(jìn)度,邏輯處理會(huì)比較復(fù)雜,同時(shí)因?yàn)椴皇亲约旱拇鎯?chǔ)服務(wù)器,不能自己根據(jù)用戶選擇的圖片順序存儲(chǔ)在服務(wù)器上(猜測(cè)是我們的服務(wù)器懶,不想寫)。
- 那就采用逐一上傳圖片的思路。如果某一張上傳成功,執(zhí)行下一張上傳任務(wù)。某一張上傳失敗,記錄失敗圖片下標(biāo)(可選擇重復(fù)上傳,或保存數(shù)據(jù)),繼續(xù)下一張上傳任務(wù).
代碼:GitHub
實(shí)現(xiàn):
@interface FGUploadImageManager ()
/**
上傳失敗的數(shù)組
*/
@property (nonatomic, strong) NSMutableArray *failedIndexs;
/**
上傳圖片數(shù)據(jù)
*/
@property (nonatomic, strong) NSArray *upLoadArray;
/**
標(biāo)識(shí)的下標(biāo)
*/
@property (nonatomic, assign) NSUInteger currentIndex;
/**
某一張圖片失敗次數(shù)
*/
@property (nonatomic, assign) NSInteger onceFailedCount;
@end
//單張圖片上傳失敗最大次數(shù)
const static NSInteger kMaxUploadCount = 3;
/**
上傳多張圖片入口
*/
- (void)upLoadImageWithImageArray:(NSArray *)imageArray
{
[self cleanData];
//初始化數(shù)據(jù)
self.failedIndexs = [NSMutableArray array];
self.upLoadArray = [NSArray arrayWithArray:imageArray];
[SVProgressHUD showWithStatus:@"正在上傳圖片..."];
[self upLoadPhotosOnceCompletion:^(NSUInteger index, BOOL isSuccess) {
if (isSuccess) {
//添加上傳成功后的動(dòng)作...(刷新UI等)
NSLog(@"上傳第%zd照片",index);
}
else {
[self.failedIndexs addObject:@(index)];
}
} completeBlock:^{
if (self.failedIndexs.count != 0) {
NSMutableString *mutableString = [NSMutableString string];
for (NSNumber *index in self.failedIndexs) {
[mutableString appendFormat:@"第%@張",index];
}
[SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"%@上傳失敗",mutableString]];
}else{
[SVProgressHUD showSuccessWithStatus:@"圖片全部上傳成功"];
}
[self cleanData];
}];
}
/**
* 遞歸上傳照片
*/
- (void)upLoadPhotosOnceCompletion:(void(^)(NSUInteger index,BOOL isSuccess))onceCompletion completeBlock:(void(^)(void))completeBlock{
//根據(jù)下標(biāo),從數(shù)組中取出圖片,轉(zhuǎn)為二進(jìn)制數(shù)據(jù)
NSData * data = UIImagePNGRepresentation(self.upLoadArray[self.currentIndex]);
//發(fā)起網(wǎng)絡(luò)請(qǐng)求
[[FGUploadHTTPRequest shareUpload] uploadPhotoAlbum:data uploadProgress:^(float percent) {
//顯示上傳的進(jìn)度
[SVProgressHUD showProgress:(CGFloat)(self.currentIndex + percent) / self.upLoadArray.count status:@"正在上傳中"];
} completeBlock:^(BOOL isSuccess) {
//如果上傳失敗,并且沒有超過最大上傳次數(shù),重新上傳
if (!isSuccess) {
self.onceFailedCount++;
if (self.onceFailedCount < kMaxUploadCount) {
[self upLoadPhotosOnceCompletion:onceCompletion completeBlock:completeBlock];
return;
}
}
//清空失敗次數(shù)
self.onceFailedCount = 0;
//記錄新的下標(biāo)index++
self.currentIndex++;
//回調(diào)一次的結(jié)果
if (onceCompletion) onceCompletion(self.currentIndex,isSuccess);
//判斷是否上傳完畢
if (self.currentIndex == self.upLoadArray.count) {
//如果是已經(jīng)上傳完了,結(jié)束
self.currentIndex = 0 ;
if (completeBlock) completeBlock();
}
else
{
//如果還沒上傳完成,繼續(xù)下一次上傳
[self upLoadPhotosOnceCompletion:onceCompletion completeBlock:completeBlock];
}
}];
}
1.當(dāng)某張上傳失敗,會(huì)嘗試上傳kMaxUploadCount次,如果仍然失敗,那就放棄本張圖片,繼續(xù)上傳下一張圖片。
2.全局的下標(biāo)標(biāo)識(shí),在完成后一定要清零,不然在同個(gè)界面再次操作的時(shí)候,標(biāo)示還保留的上次的最大值,再次調(diào)用函數(shù),會(huì)拋出異常.數(shù)組越界.
3.如果要自己修改需求.一定要寫好邊界條件.遞歸在適當(dāng)?shù)臅r(shí)候返回,不然就會(huì)成死循環(huán)了.
保留數(shù)據(jù)持續(xù)上傳的做法:
如果存在未上傳成功的圖片,我們可以將圖片扔給一個(gè)始終存在的單例或者考慮將圖片數(shù)據(jù)寫入數(shù)據(jù)庫(kù)中,這樣保證了圖片數(shù)據(jù)可以一直存在。我們要做的就是講這份數(shù)據(jù)一直不停的上傳給服務(wù)器。
用戶多張圖片感覺也是這樣,應(yīng)為這幾張圖片是用戶在自己的相冊(cè)精挑細(xì)選出來(lái)的,用戶想的就是要這圖片。不應(yīng)該就因?yàn)橐恍┰騺G失用戶的數(shù)據(jù)。當(dāng)然這是產(chǎn)品考慮的一些內(nèi)容。