背景
注:這個(gè)方法有坑。。【戳--填坑版】
最近一個(gè)半路接手的項(xiàng)目需要修改一個(gè)功能。圖片上傳。項(xiàng)目中有很多地方用到了圖片上傳這個(gè)功能,有的是單張的,有的是批量上傳的。現(xiàn)在需要全部改為批量上傳。還有新增圖片上傳的狀態(tài):未上傳、上傳中、上傳失敗、上傳成功。上傳失敗需要有一個(gè)點(diǎn)擊重傳的功能。
沒有將代碼抽離出來,就不放代碼了。涉及具體業(yè)務(wù)的部分為了保密性也不放了。。主要就是介紹一下思想,捋一下思路

動手1
因?yàn)閷e人寫的代碼不太熟悉,粗略的看過一遍后,決定先改好改的部分。然后在熟悉的過程中看看別人的思路以及牽扯到的需要修改的地方。從結(jié)果往前推。首先給圖片部分加上顯示的狀態(tài)。找到圖片顯示控件,新增控件需要的狀態(tài)。
//上傳中的半透明遮罩
@property (nonatomic, strong) UIImageView *maskView;
//點(diǎn)擊重傳的按鈕
@property (nonatomic, strong) UILabel *reUpload;
//上傳中的轉(zhuǎn)動圖片
@property (nonatomic, strong) UIImageView *uploading;
加號之后我們需要一個(gè)變量對這些控件進(jìn)行顯示與隱藏。所以我們要知道這些狀態(tài)。再來看看現(xiàn)有的這個(gè)類中提供了哪些外部更新的方法。
- (void)setImage:(UIImage *)image;
- (void)setImageUrl:(NSString *)imgUrl;
- (void)clearImage;
其中 imgUrl是上傳成功后接口返回的圖片地址,當(dāng)上傳成功后接口會按上傳順序返回圖片的一串URL,失敗的那張圖片會返回空信息。拿到結(jié)果后我們會調(diào)用這個(gè)方法去刷新。這個(gè)時(shí)候我們可以拿到 【成功】和【失敗】 的狀態(tài)。拿另外兩個(gè)【未上傳】以及【上傳中】就可以通過
- (void)setImage:(UIImage *)image
這個(gè)方法來判斷。image==nil 未上傳
動手2
接下來是圖片來源的問題。
上傳的圖片通過
- 拍照
- 相冊多張選擇
- 相冊單張選擇(【上傳失敗】需要重傳照片)
主要是修改相冊作為圖片源的部分。讓點(diǎn)擊添加的時(shí)候?yàn)槎鄰?,重傳的時(shí)候?yàn)橐粡?。批量上傳使用了別人開源的控件ZYQAssetPickerController,使用懶加載的方式初始化它。
if (_addImgIndex == _imageArray.count) {
//這個(gè)部分是新加的,_addImgIndex指的是點(diǎn)擊添加圖片的index,_imageArray存儲照片的數(shù)組,用于未上傳時(shí)候的展示
[self presentViewController:self.pickerController animated:YES completion:nil];
} else {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.allowsEditing = NO;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:imagePicker animated:YES completion:nil];
}
動手3
照片選擇完成后的回調(diào),包括圖片的顯示,圖片的
上傳。
原先是點(diǎn)一張上傳一張,不存在未上傳時(shí)候的顯示問題。所以我們需要添加一些全局變量來存儲一些東西。
@property (nonatomic, strong) NSMutableArray *imageArray; //存儲圖片
@property (nonatomic, assign) NSInteger addImgIndex; //添加照片的index;
@property (nonatomic, assign) NSInteger imageCount; //與上一個(gè)結(jié)合起來
當(dāng)前的controller實(shí)現(xiàn)ZYQAssetPickerControllerDelegate。開辟一個(gè)子線程拿到圖片后,調(diào)用存儲的方法,將圖片存入內(nèi)存。mutaFile用來存儲圖片文件用來上傳。
- (void)assetPickerController:(ZYQAssetPickerController *)picker didFinishPickingAssets:(NSArray *)assets
{
_isCamera = NO;
_imageCount = assets.count + _imageArray.count;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableArray *mutaFile = [NSMutableArray new];
for (int i=0; i<assets.count; i++) {
ZYQAsset *asset=assets[I];
[asset setGetFullScreenImage:^(UIImage *result) {
[self saveImage:result fileArr:mutaFile];
_addImgIndex += 1;
}];
}
});
}
當(dāng)所有的圖片存儲完畢后我們切回主線程,刷行UI,顯示圖片。并將圖片至于【上傳中】的狀態(tài),調(diào)用上傳文件的方法上傳文件。
- (void)saveImage:(UIImage *)image fileArr:(NSMutableArray<RdAppServiceUploadFile *> *)filePathArr
{
//省略了圖片的壓縮,存儲,以及文件的初始化
if (!_imageArray) {
_imageArray = [NSMutableArray array];
}
if (_addImgIndex == _imageArray.count) {
[_imageArray addObject:image];
[self.viewModel.showImgUrlArr addObject:@"**"];
[self.viewModel.imgUrlArr addObject:@"**"];
} else {
[_imageArray replaceObjectAtIndex:_addImgIndex withObject:image];
[self.viewModel.showImgUrlArr replaceObjectAtIndex:_addImgIndex withObject:@"**"];
[self.viewModel.imgUrlArr replaceObjectAtIndex:_addImgIndex withObject:@"**"];
}
[filePathArr addObject:file];
if (_isCamera) {
_isCamera = NO;
dispatch_async(dispatch_get_main_queue(),^{
[self.tableView reloadData];
});
[self uploadImage:filePathArr];
}
else
{
if (_imageCount == _imageArray.count) {
dispatch_async(dispatch_get_main_queue(),^{
[self.tableView reloadData];
});
[self uploadImage:filePathArr];
}
}
}
其中showImgUrlArr和imgUrlArr都是接口返回的,用**代表上傳中,##代表上傳失敗。在拿到上傳結(jié)果后給他replaceObjectAtIndex。這樣在用戶點(diǎn)擊下一步的時(shí)候,能彈框告訴用戶圖片的上傳狀態(tài),攔截當(dāng)前頁面的保存操作。
思考時(shí)間做多的地方
當(dāng)圖片分次批量上傳的時(shí)候,怎么處理這個(gè)URL對應(yīng)的替換操作。接口并沒有返回當(dāng)前這個(gè)URL指向的圖片的下標(biāo)。后來我修改了上傳的文件數(shù)組,原來這個(gè)圖片文件數(shù)組是全局變量,保存了所有要顯示的圖片,包括已經(jīng)上傳成功后的圖片。將它改為當(dāng)前需要上傳圖片,作用域只在相冊及相機(jī)回調(diào) 方法內(nèi),然后將文件命名為 0,1,2...

刷新方法里面根據(jù)showImgUrl來判斷展示什么狀態(tài)。
AddImgView *addView = [[AddImgView alloc] init];
if ([mulArr[i] isEqualToString:@"**"] || [mulArr[i] isEqualToString:@"##"]) {
//上傳中圖片 + 上傳失敗
[addView setImage:imageArr[i] reload:[mulArr[i] isEqualToString:@"##"]];
} else if ([mulArr[i] isEqualToString:@""]) {
} else {
[addView setImageUrl:imgUrlArr[i]];
}
總結(jié)
改別人的代碼總覺得很難受,中間發(fā)生過很多意外的情況,沒有自己寫的順手。因?yàn)椴磺宄暗木唧w需求,會忽略掉某些邊界以及特殊情況。只能自己一次次的debug。不過看別人的代碼學(xué)習(xí)的一種吧??偛豢赡苊總€(gè)項(xiàng)目都是從0開始的。。但是涉及到很多文件的修改真的想吐血啊。