献给初学iOS的小盆友们——微博app项目开发之八封装代码
来源:互联网 发布:双代号网络计划例题 编辑:程序博客网 时间:2024/05/09 09:22
上节课我们完成了微博数据的获取,里面用到了第三方框架的网络请求方法。这节课我们要封装网络请求业务,以及封装微博专用工具类来优化代码。
本节内容
- 封装网络请求
- 封装微博工具
- 封装账号工具类
本节资料
第八节资料
8.1 封装网络请求
我们仔细研究代码发现,我们的微博数据获取太依赖第三方框架了,如果以后想用其他网络请求方式,就要逐一找到网络请求去更改,而且以后我们很多地方都要用到网络请求,这样的话更改的工作量会很大,也会容易出错。总而言之第三方框架与我们的项目耦合性太高,需要用中间类去解耦。这里我们就创建一个新的类,专门处理网络请求,以后AFN升级,活着方法改名,或者AFN被淘汰了,直接更改工具类的方法就可以了。
创建YGHttpTool类继承自NSObject,当我们想获得微博数据的时候,希望有这么一个方法:我们只需要告诉方法url和所需参数,以及成功和失败回调即可,里面的具体步骤,不用我们再去考虑。依此设计的方法为:
+ (void)GET:(NSString *)URLString parameters:(id)parameters success:(void (^)(id responseObject))success failure:(void (^)(NSError *error))failure;
而且这里我们的方法没有返回值,因为网络数据的获取会有延迟,且是异步的,不会立马返回数据。
其执行文件的代码,就比较简单了,直接把以前的AFNetworking的请求方法搬过来即可。
loadNewStatus代码更改为:
#pragma mark - 请求最新的微博- (void)loadNewStatus{ // 创建一个参数字典 NSMutableDictionary *params = [NSMutableDictionary dictionary]; if (self.statuses.count) { params[@"since_id"] = [self.statuses[0] idstr]; } params[@"access_token"] = [YGAccountTool account].access_token; //使用YGHttpTool工具类发送get请求 [YGHttpTool GET:@"https://api.weibo.com/2/statuses/friends_timeline.json" parameters:params success:^(id responseObject) { // 请求成功的时候调用 //结束下拉刷新 [self.tableView.mj_header endRefreshing]; NSLog(@"%@",responseObject); // 获取到微博数据 转换成模型 // 获取微博字典数组 NSArray *dictArr = responseObject[@"statuses"]; // 把字典数组转换成模型数组 NSArray *statuses = (NSMutableArray *)[YGStatus mj_objectArrayWithKeyValuesArray:dictArr]; NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, statuses.count)]; // 把最新的微博数插入到最前面 [self.statuses insertObjects:statuses atIndexes:indexSet]; // 刷新表格 [self.tableView reloadData]; } failure:^(NSError *error) { }];}
可以看到这里我们使用了自己封装的网络请求工具类来处理网络请求,而不是直接使用AFNetworking的方法。虽然我们内部使用了其方法,但是当我们需要更改网络请求框架时,只需要往工具类内更改就可以了,loadNewStatus方法内的代码不需要更改。这就是代码的封装思想,请亲们细细体会。
8.2 封装微博工具类
现在又到了仔细思考的时候了,可以看到我们在YGHomeView Controller里把如何获得微博数据的种种步骤一一都告诉这个控制器了。他不仅要知道你传什么参数,你的url,还要知道你是怎么字典转模型的等等之类的细小问题。那你觉得控制器累不累啊,而且控制器的代码会越来越多,控制器就会吃成个大胖子了。他根本就不需要知道我们获取微博数据的过程,他只需要知道结果。这样不仅不利于我们维护代码,也不利于我们对整个项目逻辑的把握,所以我需要简化控制器的代码,给他好好瘦身。而且我们的代码都不够面向对象,为了把前后打通,需要建立参数模型和返回结果模型。
创建参数模型为YGStatusParam类,其代码如下:
@interface YGStatusParam : NSObject// 参数模型如何设计,直接参考接口文档的参数列表/** * 采用OAuth授权方式为必填参数,访问命令牌 */@property (nonatomic, copy) NSString *access_token;/** * 若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0。 */@property (nonatomic, copy) NSString *since_id;/** * 若指定此参数,则返回ID小于或等于max_id的微博,默认为0。 */@property (nonatomic, copy) NSString *max_id;
创建微博返回模型YGStatusResult:
/** * 用户的微博数组(CZStatus) */@property (nonatomic, strong) NSArray *statuses;/** * 用户最近微博总数 */@property (nonatomic, assign) int *total_number;
其执行文件添加的一行代码表示为,利用MJ框架,把得到的字典数组转换为模型数组,这个与YGPhoto内的代码是相同的原理:
+ (NSDictionary *)objectClassInArray{ return @{@"statuses":[YGStatus class]};}
下面我们就要设计一个微博工具类YGStatusTool,我们想设计一个简单的方法,只需要给方法提供sinceID或者maxID,以及回调函数,就可以直接获得微博数据。方法设计如下:
/** * 请求更新的微博数据 sinceId:返回比这个更大的微博数据 success:请求成功的时候回调(statuses(CZStatus模型)) failure:请求失败的时候回调,错误传递给外界 */+ (void)newStatusWithSinceId:(NSString *)sinceId success:(void(^)(NSArray *statuses))success failure:(void(^)(NSError *error))failure;/** * 请求更多的微博数据 * * @param maxId 返回小于等于这个id的微博数据 * @param success 请求成功的时候回调 * @param failure 请求失败的时候回调 */+ (void)moreStatusWithMaxId:(NSString *)maxId success:(void(^)(NSArray *statuses))success failure:(void(^)(NSError *error))failure;
这个方法是不是看起来很清爽,然后我们把内部实现的代码从控制器里搬到他的执行文件就可以啦,代码就不赘述了。
然后我们根据上述创建的类去修改控制器里的代码:
loadNewStatus的代码就变为:
- (void)loadNewStatus{ NSString *sinceId = nil; if (self.statuses.count) { // 有微博数据,才需要下拉刷新 sinceId = [self.statuses[0] idstr]; } [YGStatusTool newStatusWithSinceId:sinceId success:^(NSArray *statuses) { // 结束下拉刷新 [self.tableView.mj_header endRefreshing]; NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, statuses.count)]; // 把最新的微博数插入到最前面 [self.statuses insertObjects:statuses atIndexes:indexSet]; // 刷新表格 [self.tableView reloadData]; } failure:^(NSError *error) { }];}
同样的loadMoreStatus方法就变为:
#pragma mark - 请求更多旧的微博- (void)loadMoreStatus{ NSString *maxIdStr = nil; if (self.statuses.count) { // 有微博数据,才需要下拉刷新 long long maxId = [[[self.statuses lastObject] idstr] longLongValue] - 1; maxIdStr = [NSString stringWithFormat:@"%lld",maxId]; }[YGStatusTool moreStatusWithMaxId:maxIdStr success:^(NSArray *statuses) { // 结束上拉刷新 [self.tableView.mj_footer endRefreshing]; // 把数组中的元素添加进去 [self.statuses addObjectsFromArray:statuses]; // 刷新表格 [self.tableView reloadData];} failure:^(NSError *error) {}]; }
这样看我们的代码是不是很清爽了。
8.3 封装账号工具类
根据刚才的封装思想我们就会联想到,之前在YGOAuthViewController内accessTokenWithCode方法内,也是使用了网络请求,而且请求参数也没有设计成模型。所以现在我们来该是给这段代码做手术。我们首先设计一个获取access token 时所用到的参数模型YGAccountParam类,代码如下:
/** * AppKey */@property (nonatomic, copy) NSString *client_id;/** * AppSecret */@property (nonatomic, copy) NSString *client_secret;/** * 请求的类型,填写authorization_code */@property (nonatomic, copy) NSString *grant_type;/** * 调用authorize获得的code值 */@property (nonatomic, copy) NSString *code;/** * 回调地址 */@property (nonatomic, copy) NSString *redirect_uri;
当我们仔细观察accessTokenWithCode的源代码发现,这里的网络请求也是直接使用AFNetworking框架的,为了有同样的解耦效果,我们也需要在YGHttpTool的类中增加一个post请求方法,其代码如下:
+ (void)Post:(NSString *)URLString parameters:(id)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure{ // 创建请求管理者 AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; [mgr POST:URLString parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { if (success) { success(responseObject); } } failure:^(AFHTTPRequestOperation *operation, NSError *error) { if (failure) { failure(error); } }];}
最后在YGAccessToken的类中增加一个获取access token的方法。代码如下:
+ (void)accountWithCode:(NSString *)code success:(void (^)())success failure:(void (^)(NSError *))failure{ // 创建参数模型 YGAccountParam *param = [[YGAccountParam alloc] init]; param.client_id = YGClient_id; param.client_secret = YGClient_secret; param.grant_type = @"authorization_code"; param.code = code; param.redirect_uri = YGRedirect_uri; [YGHttpTool Post:@"https://api.weibo.com/oauth2/access_token" parameters:param.mj_keyValues success:^(id responseObject) { // 字典转模型 YGAccount *account = [YGAccount accountWithDict:responseObject]; // 保存账号信息: // 数据存储一般我们开发中会搞一个业务类,专门处理数据的存储 // 以后我不想归档,用数据库,直接改业务类 [YGAccountTool saveAccount:account]; if (success) { success(); } } failure:^(NSError *error) { if (failure) { failure(error); } }];}
有了工具类我们就可以更改accessTokenWithCode方法的源代码了,更改如下:
#pragma mark - 换取accessToken- (void)accessTokenWithCode:(NSString *)code{ [YGAccountTool accountWithCode:code success:^{ // 进入主页或者新特性,选择窗口的根控制器 [YGRootVcTool chooseRootViewController:YGKeyWindow]; } failure:^(NSError *error) { }];}
是不是感觉比以前清爽很多,逻辑也更清楚,就一句代码,表明的就是我要获取account信息啦,但是其内部是怎么实现的就不要告诉我控制器了,那是其他人的事。
今天先讲这么多吧,如果今天的代码你都能领会并且熟练应用的话,你就离一个高级程序员不远了。下节课讲继续会提到封装的概念,尽情期待。
- 献给初学iOS的小盆友们——微博app项目开发之八封装代码
- 献给初学iOS的小盆友们——微博app项目开发之十二自定义cell代码补全
- 献给初学iOS的小盆友们——微博app项目开发之二自定义tabBar
- 献给初学iOS的小盆友们——微博app项目开发之三设置导航条
- 献给初学iOS的小盆友们——微博app项目开发之四设置导航功能
- 献给初学iOS的小盆友们——微博app项目开发之五新特性界面
- 献给初学iOS的小盆友们——微博app项目开发之六OAuth授权
- 献给初学iOS的小盆友们——微博app项目开发之十五微博配图
- 献给初学iOS的小盆友们——微博app项目开发之七第一次获取微博数据
- 献给初学iOS的小盆友们——微博app项目开发之九未读数设置以及后台播放
- 献给初学iOS的小盆友们——微博app项目开发之十显示昵称与最新微博数
- 献给初学iOS的小盆友们——微博app项目开发之十一自定义cell和MVVM模式
- 献给初学iOS的小盆友们——微博app项目开发之十三微博时间和来源处理
- 献给初学iOS的小盆友们——微博app项目开发之十六搭建发送微博界面(上)
- 献给初学iOS的小盆友们——微博app项目开发之十七搭建发送微博界面(中)
- 献给初学iOS的小盆友们——微博app项目开发之十八搭建发送微博界面(下)
- 献给初学iOS的小盆友们——微博app项目开发之十四转发微博修正以及添加微博工具条
- 献给初学iOS的小盆友们------微博app项目开发之一项目初始化
- Mininet 自定义网络拓扑
- MediaPlayer简单理解
- 【慕课笔记】U1 类和对象 第6节 JAVA中的static使用之静态变量
- Socket(套接字)通信笔记
- 超级有用的git reset --hard和git revert命令
- 献给初学iOS的小盆友们——微博app项目开发之八封装代码
- 欢迎使用CSDN-markdown编辑器
- 【YouXue 1019】鹿死谁手
- 框框架架
- [Maven实战](5)Archetype生成项目骨架
- 题解: HDU 4004 The Frog's Games (二分搜索)
- 动态规划的基本概念和基本模型构成
- 如何让Android自适应不同分辨率或不同屏幕大小的layout布局
- 90. Compare Version Numbers