最近遇到问题就是多张图片上传服务器该怎么设置.刚开始想到的第一想法就是创建个串行队列.吧这个串行队列放在子线程.循环去上传.首先,在这里.我们首先模拟一个网络请求的方法.
#pragma mark -模拟网络请求-
- (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.定个全局标示.来记录上传的个数
@property(nonatomic,assign)NSUIntegerindex;
2.分发任务,请求
//创建一个串行队列
dispatch_queue_tqueue =dispatch_queue_create("com.xxx.www",NULL);
//分发任务,放到子线程中
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 发说说有图片那样的进度提示,就不好做了.
接下来就说说我们的第二种方法,第二方法用到递归算法,主要的思想就是:递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回.这里感谢我的好友顾梦晓,当时是和他讨论这个问题时,才想出的这个解决方法.
二.递归算法
1.创建几个全局标识
//图片数据源
@property(nonatomic,strong)NSMutableArray*images;
//标示的下标
@property(nonatomic,assign)NSUIntegerindex;
//第一种失败回调所需存储失败数据
@property(nonatomic,strong)NSMutableArray*faileIndexs;
2.测试调用的函数
- (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.失败回调1的情况处理
if(isSuccess) {
if(index ==_images.count) {
NSLog(@"上传完毕,失败的张数为:%@",_faileIndexs);
}
NSLog(@"上传过程第%lu张成功",index);
}else{
if(index ==_images.count) {
NSLog(@"上传完毕,失败的张数为:%@",_faileIndexs);
}
[_faileIndexsaddObject:@(index)];
NSLog(@"上传过程第%lu张失败",index);
}
//2.失败回调2的情况处理
/*
if (isSuccess) {
if (index == _images.count) {
//上传所有图片的成功
NSLog(@"上传所有的成功");
}
NSLog(@"上传过程第%lu张成功",index);
}else{
//上传图片失败
NSLog(@"上传图片失败,止于第%lu张",index);
}
*/
}];
}
3.上传图片的递归算法函数
- (void)updateImage:(UIImage*)image completion:(void(^)(NSUIntegerindex,BOOLisSuccess))completion{
//压缩图片,看自己的要求压缩比例设置compressionQuality参数,此参数最好在2-7之间.太小泽压缩容易失真,太大占用内存太大
NSData*dataImage =UIImageJPEGRepresentation(image,1);
//转换的参数有四个枚举,分别为:
// NSDataBase64Encoding64CharacterLineLength = 1UL << 0,将最大行长度设置为64个字符,插入你所指定的那一行
// NSDataBase64Encoding76CharacterLineLength = 1UL << 1,将最大行长度设置为76个字符,插入你所指定的那一行
//以下可以控制结束行数的:
// NSDataBase64EncodingEndLineWithCarriageReturn = 1UL << 4,设置最大行长度64个字符,并可以指定在哪行结束
// NSDataBase64EncodingEndLineWithLineFeed = 1UL << 5,指定最大行长度76个字符,并指定在哪行结束
//这个转换可以自行google base64加密
NSString*imageStr = [dataImagebase64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
[selfGET:@"url"parameter:@{@"youparmater": imageStr,@"id": [NSStringstringWithFormat:@"%u",arc4random() %2]}success:^(idrespondObject) {
//如果上传成功
_index++;
//回调
completion(_index,YES);
if(_index==_images.count) {
//全部上传成功
//清空标示
_index=0;
return;
}
//继续下一行张
[selfupdateImage:_images[_index]completion:completion];
}failure:^(NSError*error) {
//先判断是否是最后一张,如果是,则返回
if(_index==_images.count-1) {
completion(_index+1,NO);
//清空标示
_index=0;
return;
}
//失败,分两种情况:
//1.跳过失败的那张,返回失败信息,继续下张上传
_index++;
completion(_index,NO);
[selfupdateImage:_images[_index]completion:completion];
//2.直接返回,不在进行接下来的上传工作
/*
completion(_index + 1, NO);
//清空标示
_index = 0;
return ;
*/
}];
}
备注:
1.这里列举了两种处理方法:第一种是:只要是失败了就直接停止在那张就可以了,提示用户继续或者取消,这是根据回调的标识下标就可以处理数据源来重试或者取消.第二种方法就是:一张失败后,回调记录,接着下张继续上传.在全部操作完成后再提示用户失败的图片.
2.在上传图片的递归函数中,在递归调用 block 的时候切记要将第一次传进来的 blcok 递归传递给后一个函数,不然下个函数的 block 就会被替代.成功或者失败的回调在图片张数大于1时,永远不会被回调了.
3.如果要自己修改需求.一定要写好边界条件.递归在适当的时候返回,不然就会成死循环了.
4.全局的下标标识,在完成后一定要清零,不然在同个界面再次操作的时候,标示还保留的上次的最大值,再次调用函数,会抛出异常.数组越界.
三.保留数据的做法.
这点笔者并没有写,就谈谈思路,就是保留数据.当用户点击了保存后,应该把数据保存到数据库,在上传服务器,这时候就不会让提示失败,我们会始终把数据上传到服务器为止.我看在处理蓝牙接受到的数据就是这样处理的,应为该数据为不保留性,过了就会没有了,但是用户要用这块数据,不能丢失用户的数据,所以我们应该将此数据保留到数据库,上传服务器成功为止.用户多张图片感觉也是这样,应为这几张图片是用户在自己的相册精挑细选出来的,用户想的就是要这图片.不应该就因为一些原因丢失用户的数据.哟感兴趣的小伙伴可以试试.
今天就写到这了.周六早晨就下雨,感觉挺舒服清爽的!
补丁:Demo 地址 2016/8/17