标签:
通常耗时的操作都会放在子线程里处理,然后再回到主线程来显示。下面举几个例子:
版本迭代一定要注意兼容老版本,比如新增了字段或者去掉了某些不再使用的字段,不能引起应用闪退。我们这里只谈程序代码兼容新老版本问题,不考虑业务。因为业务是要求后台来兼容的,通常接口会有版本号控制,用于兼容不同版本的客户端。
对于任何一个App,当可以升级的时候,不会是所有用户就立刻去升级,通常会有很大一部分的用户是不愿意立刻升级的。原因会有很多种,比如我这种的就不会频繁升级,因为对于我来说,这个App并不是天天用,没有必要升级。
那么,我们在iOS开发时,如何去兼容老版本的,保证新版本的增加或者删减不会影响到老版本呢?其实这个问题似乎并不是说有没有新、老版本问题,更重要的是程序的健壮性问题。
对于我们做前端的,永远不要相信后台一定会按照原先约定返回我们想要的数据结构以及所有字段。
假设接口返回来的数据是这样的,我们需要通过类型判断,确保不会因为接口变化返回无效数据而引起闪退。当然,当接口返回的数据结构与我们原先约定的不一样时,通常是因为后台出错了,因此为了程序更健壮,我们应该要容得下后台的错误:
AFHTTPRequestOperation *op = [selfPostRequestWithUrl:urlparams:paramscompletion:^(id responseObject) {
BOOL isSuccess = NO;
if ([responseObjectisKindOfClass:[NSDictionary class]]) {
NSDictionary *response = responseObject[@"response"];
if ([responseisKindOfClass:[NSDictionary class]]) {
NSArray *resultList = response[@"resultList"];
if ([resultListisKindOfClass:[NSArray class]]) {
NSArray *listModels = [HYBCosmesisModelobjectArrayWithKeyValuesArray:resultList];
isSuccess = YES;
completion(listModels);
}
}
}
if (!isSuccess) {
// 表示出错
completion(nil);
}
}errorBlock:^(NSError *error) {
errorBlock(error);
}];
而我们在使用的时候,对于字符串、数组、字典都应该要做一下类型判断和空处理。比如:
if ([responseisKindOfClass:[NSDictionary class]]) {
NSString *value = response[@"blogName"];
if (!kIsEmptyString(value)) {
// Do my job
}
NSArray *array = response[@"array"];
if ([arrayisKindOfClass:[NSArray class]]) {
// Do my job
}
}
对于业务方面的话,由后台来做版本控制,通过在接口做添加公共参数,[email protected]
?要调用的是哪个版本的接口。
这个问题非常简单,但是对于新手就不太清楚了。在很多小公司里,前端好像什么都不需要管,只等后台给你一个接口及参数说明就可以了,根本不清楚后端为什么要这么设计这个接口。
那笔者也来聊聊如何与后端服务器交互:
好了,就扯谈这些吧~
使用Dispatch Group追加block到Global Group Queue,这些block如果全部执行完毕,就会执行Main Dispatch Queue中的结束处理的block。
当放到group中的所有请求都完成时,才会回调dispatch group notify的block:
dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_tgroup = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /*加载图片1 */ });
dispatch_group_async(group, queue, ^{ /*加载图片2 */ });
dispatch_group_async(group, queue, ^{ /*加载图片3 */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并图片
});
这个不太清楚想问什么,笔者翻看了看GCD中dispatch group t里,也没有什么可以设置同一个组内的任务依赖关系的,就看到dispatch group wait这个API:
long
dispatch_group_wait(dispatch_group_tgroup, dispatch_time_ttimeout);
这个API是等待group中的所有任务都执行完毕才能继续往下执行其它任务。它是同步地等待任务执行完毕。比如,A、B、C、D四个任务,要求A、B执行完毕后,C、D才能开始执行,那么可以通过这样做:
dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_tgroup = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /* 任务A */ });
dispatch_group_async(group, queue, ^{ /* 任务B */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
dispatch_group_async(group, queue, ^{ /* 任务C */ });
dispatch_group_async(group, queue, ^{ /* 任务D */ });
});
或者可以这样:
dispatch_queue_tqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_tgroup = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /* 任务A */ });
dispatch_group_async(group, queue, ^{ /* 任务B */ });
// 同步等待A、B执行
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
// 重新创建组
group = dispatch_group_create();
dispatch_group_async(group, queue, ^{ /* 任务C */ });
dispatch_group_async(group, queue, ^{ /* 任务D */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// C、D执行完毕后,想干嘛就干嘛去吧
});
不知道笔者对题目的理解是否到位,上面的代码是随手写的,可能单词会写错~~~
笔者所能想到的方案:
笔者针对这个问题,第一想到的就是通过图片的摘要验证。服务端在接口中返回用户信息时,连同图片的摘要(md5)值也下发到客户端,然后每次App登录时,服务端都将最新的用户信息返回来,客户端将本地所缓存的用户头像取出,也生成摘要(md5)五,与服务端所返回来的md5值比较,若相同表示没有头像没有修改过;若不相同,表示头像已经修改过。
缺点:只要重新登录或者App在后台自动登录后,才能更新。也就是说,如果用户没有退出登录,或者没有过期而不会自动登录,头像也没有更新得了。
在微博上收集到大家的方案。给URL添加一个参数version,当图片修改之后,URL的version发生变化,那么就会重新下载图片来缓存。
缺点:与方案一类似,要求重新请求数据才能得到最新的URL。
在修改图片时,要求不能使用相同的名字,这样链接路径是一样的,但是因为名字不同而找不到。此时,就会重新获取图片而不是缓存的。可以在文件名中带上前缀进行上传,譬如avatar-3/v1.jpg,更新后改为avatar-3/v2.jpg。
客户端在请求头加上If-Modified-Since字段,表明请求此时间后最新的文件资源,服务端也会在响应头返回这个last-modified字段表示上次修改时间。
标签:
原文地址:http://www.cnblogs.com/wyk19910103/p/5483416.html