首页 > 代码库 > iOS开发项目篇—36封装微博业务
iOS开发项目篇—36封装微博业务
iOS开发项目篇—36封装微博业务
一、简单说明
1.请求参数面向模型
2.请求结果面向模型
3.对控制器来说应该屏蔽业务细节。不让控制器关心(知道)业务细节,它只需要知道自己在做某个业务
@通过一个专门的业务处理类:处理微博业务细节
说明:
业务:加载新的微博首页数据
实现:给新浪服务器发送一个GET请求
业务:加载更多的首页微博数据
实现1:给新浪服务器发送一个GET请求
实现2:去沙盒中加载以前离线缓存的微博数据
二、实现
1.新建一个微博业务处理类,继承自NSObject
微博业务处理类中的代码设计:
YYStatusTool.h文件
1 // 2 // YYStatusTool.h 3 // 微博业务类:处理跟微博相关的一切业务,比如加载微博数据、发微博、删微博 4 5 #import <Foundation/Foundation.h> 6 #import "YYHomeStatusesParam.h" 7 #import "YYHomeStatusesResult.h" 8 9 @interface YYStatusTool : NSObject10 /**11 * 加载首页的微博数据12 *13 * @param param 请求参数14 * @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)15 * @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)16 */17 18 +(void)homeStatusesWithParam:(YYHomeStatusesParam *)param success:(void (^)(YYHomeStatusesResult *result))success failure:(void(^)(NSError *error))failure;19 20 @end
YYStatusTool.m文件
1 // 2 // YYStatusTool.m 3 // 4 5 #import "YYStatusTool.h" 6 #import "YYHttpTool.h" 7 #import "MJExtension.h" 8 @implementation YYStatusTool 9 10 +(void)homeStatusesWithParam:(YYHomeStatusesParam *)param success:(void (^)(YYHomeStatusesResult *))success failure:(void (^)(NSError *))failure11 {12 //把请求参数模型转换为字典13 NSDictionary *params=param.keyValues;14 15 [YYHttpTool get:@"https://api.weibo.com/2/statuses/home_timeline.json" params:params success:^(id responseObj) {16 if (success) {17 //把获取的数据(返回结果)由字典转换为模型18 YYHomeStatusesResult *result=[YYHomeStatusesResult objectWithKeyValues:responseObj];19 success(result);20 }21 } failure:^(NSError *error) {22 if (failure) {23 failure(error);24 }25 }];26 }27 @end
2.新建一个类(模型),封装加载首页微博数据的请求参数
查看新浪官方要求的请求参数:
该类中的代码设计:
YYHomeStatusesParam.h
1 // 2 // YYHomeStatusesParam.h 3 //封装加载首页微博数据的请求参数 4 5 #import <Foundation/Foundation.h> 6 7 @interface YYHomeStatusesParam : NSObject 8 /**access_token false string 采用OAuth授权方式为必填参数,其他授权方式不需要此参数,OAuth授权后获得。*/ 9 @property(nonatomic,copy)NSString *access_token;10 11 /**since_id false int64 若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0。*/12 @property(nonatomic,strong)NSNumber *since_id;13 14 /**max_id false int64 若指定此参数,则返回ID小于或等于max_id的微博,默认为0。*/15 @property(nonatomic,strong)NSNumber *max_id;16 17 /**count false int 单页返回的记录条数,最大不超过100,默认为20。*/18 @property(nonatomic,strong)NSNumber *count;19 20 //说明:这里把int数据包装成NSNumber对象,是为了防止字典中出现空值21 @end
3.新建一个类(模型),封装加载首页微博数据的返回结果
该类中的代码设计:
YYHomeStatusesResult.h文件
1 // 2 // YYHomeStatusesResult.h 3 //封装加载首页微博数据的返回结果 4 5 #import <Foundation/Foundation.h> 6 7 @interface YYHomeStatusesResult : NSObject 8 /**微博数组 装着YYStatus模型*/ 9 @property(nonatomic,strong)NSArray *statuses;10 /**近期的微博总数*/11 @property(nonatomic,assign)int total_number;12 @end
YYHomeStatusesResult.m文件
1 // 2 // YYHomeStatusesResult.m 3 // 4 5 #import "YYHomeStatusesResult.h" 6 #import "MJExtension.h" 7 #import "YYStatusModel.h" 8 9 @implementation YYHomeStatusesResult10 -(NSDictionary *)objectClassInArray11 {12 return @{@"statuses":[YYStatusModel class]};13 }14 @end
说明:这里使用了第三方框架,完成了字典转模型的操作。
4.在首页控制器代码中的设计
YYHomeTableViewController.m文件
1 // 2 // YYHomeTableViewController.m 3 // 4 5 #import "YYHomeTableViewController.h" 6 #import "YYOneViewController.h" 7 #import "YYTitleButton.h" 8 #import "YYPopMenu.h" 9 #import "YYAccountModel.h" 10 #import "YYAccountTool.h" 11 //#import "AFNetworking.h" 12 #import "UIImageView+WebCache.h" 13 #import "YYUserModel.h" 14 #import "YYStatusModel.h" 15 #import "MJExtension.h" 16 #import "YYloadStatusesFooter.h" 17 //#import "YYHttpTool.h" 18 #import "YYHomeStatusesParam.h" 19 #import "YYHomeStatusesResult.h" 20 #import "YYStatusTool.h" 21 22 @interface YYHomeTableViewController ()<YYPopMenuDelegate> 23 @property(nonatomic,assign)BOOL down; 24 @property(nonatomic,strong)NSMutableArray *statuses; 25 @property(nonatomic,strong)YYloadStatusesFooter *footer; 26 @property(nonatomic,strong) YYTitleButton *titleButton; 27 @end 28 29 @implementation YYHomeTableViewController 30 31 #pragma mark- 懒加载 32 -(NSMutableArray *)statuses 33 { 34 if (_statuses==nil) { 35 _statuses=[NSMutableArray array]; 36 } 37 return _statuses; 38 } 39 - (void)viewDidLoad 40 { 41 [super viewDidLoad]; 42 43 //设置导航栏内容 44 [self setupNavBar]; 45 46 //集成刷新控件 47 [self setupRefresh]; 48 49 //设置用户的昵称为标题 50 //先显示首页标题,延迟两秒之后变换成用户昵称 51 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 52 [self setupUserInfo]; 53 }); 54 } 55 56 /** 57 *设置用户的昵称为标题 58 */ 59 -(void)setupUserInfo 60 { 61 // //1.封装请求参数 62 // NSMutableDictionary *params=[NSMutableDictionary dictionary]; 63 // params[@"access_token"] =[YYAccountTool accountModel].access_token; 64 // params[@"uid"]=[YYAccountTool accountModel].uid; 65 // 66 // //2.发送网络请求 67 // [YYHttpTool get:@"https://api.weibo.com/2/users/show.json" params:params success:^(id responseObj) { 68 // //字典转模型 69 // YYUserModel *user=[YYUserModel objectWithKeyValues:responseObj]; 70 // //设置标题 71 // [self.titleButton setTitle:user.name forState:UIControlStateNormal]; 72 // // 存储账号信息(需要先拿到账号) 73 // YYAccountModel *account=[YYAccountTool accountModel]; 74 // account.name=user.name; 75 // //存储 76 // [YYAccountTool save:account]; 77 // } failure:^(NSError *error) { 78 // YYLog(@"请求失败"); 79 // }]; 80 } 81 82 //集成刷新控件 83 -(void)setupRefresh 84 { 85 // 1.添加下拉刷新控件 86 UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; 87 [self.tableView addSubview:refreshControl]; 88 89 //2.监听状态 90 [refreshControl addTarget:self action:(@selector(refreshControlStateChange:)) forControlEvents:UIControlEventValueChanged]; 91 92 //3.让刷新控件自动进入到刷新状态 93 [refreshControl beginRefreshing]; 94 95 //4.手动调用方法,加载数据 96 //模拟网络延迟,延迟2.0秒 97 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 98 [self refreshControlStateChange:refreshControl]; 99 });100 101 //5.上拉刷新数据102 YYloadStatusesFooter *footer=[YYloadStatusesFooter loadFooter];103 self.tableView.tableFooterView=footer;104 self.footer=footer;105 }106 107 /**108 * 当下拉刷新控件进入刷新状态(转圈圈)的时候会自动调用109 */110 -(void)refreshControlStateChange:(UIRefreshControl *)refreshControl111 {112 [self loadNewStatuses:refreshControl];113 114 // //1.封装请求参数115 // NSMutableDictionary *params=[NSMutableDictionary dictionary];116 // params[@"access_token"] =[YYAccountTool accountModel].access_token;117 // //取出当前微博模型中的第一条数据,获取第一条数据的id118 // YYStatusModel *firstStatus=[self.statuses firstObject];119 // if (firstStatus) {120 // params[@"since_id"]=firstStatus.idstr;121 // }122 // 123 // //2.发送网络请求124 //https://api.weibo.com/2/statuses/home_timeline.json125 // [YYHttpTool get:@"https://api.weibo.com/2/statuses/home_timeline.json" params:params success:^(id responseObj) {126 // 127 // // 微博字典 -- 数组128 // NSArray *statusDictArray = responseObj[@"statuses"];129 // //微博字典数组---》微博模型数组130 // NSArray *newStatuses =[YYStatusModel objectArrayWithKeyValuesArray:statusDictArray];131 // 132 // //把新数据添加到旧数据的前面133 // NSRange range=NSMakeRange(0, newStatuses.count);134 // NSIndexSet *indexSet=[NSIndexSet indexSetWithIndexesInRange:range];135 // [self.statuses insertObjects:newStatuses atIndexes:indexSet];136 // YYLog(@"刷新了--%d条新数据",newStatuses.count);137 // 138 // //重新刷新表格139 // [self.tableView reloadData];140 // //让刷新控件停止刷新(回复默认的状态)141 // [refreshControl endRefreshing];142 // [self showNewStatusesCount:newStatuses.count];143 // 144 // } failure:^(NSError *error) {145 // 146 // YYLog(@"请求失败");147 // //让刷新控件停止刷新(回复默认的状态)148 // [refreshControl endRefreshing];149 // }];150 }151 152 #pragma mark-加载微博数据153 -(void)loadNewStatuses:(UIRefreshControl *)refreshControl154 {155 //1.封装请求参数156 YYHomeStatusesParam *param=[[YYHomeStatusesParam alloc]init];157 param.access_token=[YYAccountTool accountModel].access_token;158 YYStatusModel *firstStatus=[self.statuses firstObject];159 if (firstStatus) {160 param.since_id=@([firstStatus.idstr longLongValue]);161 }162 163 //2.加载微博数据164 [YYStatusTool homeStatusesWithParam:param success:^(YYHomeStatusesResult *result) {165 // // 微博字典 -- 数组166 // NSArray *statusDictArray = responseObj[@"statuses"];167 // //微博字典数组---》微博模型数组168 // NSArray *newStatuses =[YYStatusModel objectArrayWithKeyValuesArray:statusDictArray];169 170 //获取最新的微博数组171 NSArray *newStatuses=result.statuses;172 173 //把新数据添加到旧数据的前面174 NSRange range=NSMakeRange(0, newStatuses.count);175 NSIndexSet *indexSet=[NSIndexSet indexSetWithIndexesInRange:range];176 [self.statuses insertObjects:newStatuses atIndexes:indexSet];177 YYLog(@"刷新了--%d条新数据",newStatuses.count);178 179 //重新刷新表格180 [self.tableView reloadData];181 //让刷新控件停止刷新(回复默认的状态)182 [refreshControl endRefreshing];183 [self showNewStatusesCount:newStatuses.count];184 185 } failure:^(NSError *error) {186 YYLog(@"请求失败");187 //让刷新控件停止刷新(回复默认的状态)188 [refreshControl endRefreshing];189 190 }];191 192 }193 194 /**195 * 加载更多的微博数据196 */197 - (void)loadMoreStatuses198 {199 // 1.封装请求参数200 // NSMutableDictionary *params = [NSMutableDictionary dictionary];201 // params[@"access_token"] = [YYAccountTool accountModel].access_token;202 // YYStatusModel *lastStatus = [self.statuses lastObject];203 // if (lastStatus) {204 // params[@"max_id"] = @([lastStatus.idstr longLongValue] - 1);205 // }206 207 // //2.发送网络请求208 // [YYHttpTool get:@"https://api.weibo.com/2/statuses/home_timeline.json" params:params success:^(id responseObj) {209 // // 微博字典数组210 // NSArray *statusDictArray = responseObj[@"statuses"];211 // // 微博字典数组 ---> 微博模型数组212 // NSArray *newStatuses = [YYStatusModel objectArrayWithKeyValuesArray:statusDictArray];213 // 214 // // 将新数据插入到旧数据的最后面215 // [self.statuses addObjectsFromArray:newStatuses];216 // 217 // // 重新刷新表格218 // [self.tableView reloadData];219 // 220 // // 让刷新控件停止刷新(恢复默认的状态)221 // [self.footer endRefreshing];222 //223 // } failure:^(NSError *error) {224 // YYLog(@"请求失败--%@", error);225 // // 让刷新控件停止刷新(恢复默认的状态)226 // [self.footer endRefreshing];227 // }];228 229 //1.封装请求参数230 YYHomeStatusesParam *param=[[YYHomeStatusesParam alloc]init];231 param.access_token=[YYAccountTool accountModel].access_token;232 YYStatusModel *lastStatus=[self.statuses lastObject];233 if (lastStatus) {234 param.max_id=@([lastStatus.idstr longLongValue]-1);235 }236 237 //2.发送网络请求238 [YYStatusTool homeStatusesWithParam:param success:^(YYHomeStatusesResult *result) {239 // // 微博字典数组240 // NSArray *statusDictArray = responseObj[@"statuses"];241 // // 微博字典数组 ---> 微博模型数组242 // NSArray *newStatuses = [YYStatusModel objectArrayWithKeyValuesArray:statusDictArray];243 244 //获取最新的微博数组245 NSArray *newStatuses=result.statuses;246 // 将新数据插入到旧数据的最后面247 [self.statuses addObjectsFromArray:newStatuses];248 // 重新刷新表格249 [self.tableView reloadData];250 // 让刷新控件停止刷新(恢复默认的状态)251 [self.footer endRefreshing];252 } failure:^(NSError *error) {253 YYLog(@"请求失败--%@", error);254 // 让刷新控件停止刷新(恢复默认的状态)255 [self.footer endRefreshing];256 }];257 }258 259 /**260 * 提示用户最新的微博数量261 *262 * @param count 最新的微博数量263 */264 -(void)showNewStatusesCount:(int)count265 {266 //1.创建一个label267 UILabel *label=[[UILabel alloc]init];268 269 //2.设置label的文字270 if (count) {271 label.text=[NSString stringWithFormat:@"共有%d条新的微博数据",count];272 }else273 {274 label.text=@"没有最新的微博数据";275 }276 277 //3.设置label的背景和对其等属性278 label.backgroundColor=[UIColor colorWithPatternImage:[UIImage imageWithName:@"timeline_new_status_background"]];279 label.textAlignment=UITextAlignmentCenter;280 label.textColor=[UIColor whiteColor];281 282 //4.设置label的frame283 label.x=0;284 label.width=self.view.width;285 label.height=35;286 // label.y=64-label.height;287 label.y=self.navigationController.navigationBar.height+20-label.height;288 289 //5.把lable添加到导航控制器的View上290 // [self.navigationController.view addSubview:label];291 //把label添加到导航控制器上,显示在导航栏的下面292 [self.navigationController.view insertSubview:label belowSubview:self.navigationController.navigationBar];293 294 //6.设置动画效果295 CGFloat duration=0.75;296 //设置提示条的透明度297 label.alpha=0.0;298 [UIView animateWithDuration:duration animations:^{299 //往下移动一个label的高度300 label.transform=CGAffineTransformMakeTranslation(0, label.height);301 label.alpha=1.0;302 } completion:^(BOOL finished) {//向下移动完毕303 304 //延迟delay秒的时间后,在执行动画305 CGFloat delay=0.5;306 307 [UIView animateKeyframesWithDuration:duration delay:delay options:UIViewAnimationOptionCurveEaseOut animations:^{308 309 //恢复到原来的位置310 label.transform=CGAffineTransformIdentity;311 label.alpha=0.0;312 313 } completion:^(BOOL finished) {314 315 //删除控件316 [label removeFromSuperview];317 }];318 }];319 }320 321 /**322 UIViewAnimationOptionCurveEaseInOut = 0 << 16, // 开始:由慢到快,结束:由快到慢323 UIViewAnimationOptionCurveEaseIn = 1 << 16, // 由慢到块324 UIViewAnimationOptionCurveEaseOut = 2 << 16, // 由快到慢325 UIViewAnimationOptionCurveLinear = 3 << 16, // 线性,匀速326 */327 328 /**设置导航栏内容*/329 -(void)setupNavBar330 {331 self.navigationItem.leftBarButtonItem=[UIBarButtonItem itemWithImageName:@"navigationbar_friendsearch" highImageName:@"navigationbar_friendsearch_highlighted" target:self action:@selector(friendsearch)];332 self.navigationItem.rightBarButtonItem=[UIBarButtonItem itemWithImageName:@"navigationbar_pop" highImageName:@"navigationbar_pop_highlighted" target:self action:@selector(pop)];333 334 //设置导航栏按钮335 YYTitleButton *titleButton=[[YYTitleButton alloc]init];336 337 //设置尺寸338 // titleButton.width=100;339 titleButton.height=35;340 341 //设置文字342 YYAccountModel *account= [YYAccountTool accountModel];343 NSString *name=account.name;344 NSLog(@"%@",name);345 // name=@"yangye";346 //判断:如果name有值(上一次登录的用户名),那么就使用上次的,如果没有那么就设置为首页347 if (name) {348 [titleButton setTitle:name forState:UIControlStateNormal];349 }else{350 [titleButton setTitle:@"首页" forState:UIControlStateNormal];351 }352 //设置图标353 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_down"] forState:UIControlStateNormal];354 //设置背景355 [titleButton setBackgroundImage:[UIImage resizedImage:@"navigationbar_filter_background_highlighted"] forState:UIControlStateHighlighted];356 357 //设置尺寸358 // titleButton.width=100;359 // titleButton.height=35;360 //监听按钮的点击事件361 [titleButton addTarget:self action:@selector(titleButtonClick:) forControlEvents:UIControlEventTouchUpInside];362 self.navigationItem.titleView=titleButton;363 self.titleButton=titleButton;364 }365 -(void)titleButtonClick:(UIButton *)titleButton366 {367 368 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_up"] forState:UIControlStateNormal];369 370 UITableView *tableView=[[UITableView alloc]init];371 [tableView setBackgroundColor:[UIColor yellowColor]];372 YYPopMenu *menu=[YYPopMenu popMenuWithContentView:tableView];373 [menu showInRect:CGRectMake(60, 55, 200, 200)];374 menu.dimBackground=YES;375 376 menu.arrowPosition=YYPopMenuArrowPositionRight;377 menu.delegate=self;378 }379 380 381 #pragma mark-YYPopMenuDelegate382 //弹出菜单383 -(void)popMenuDidDismissed:(YYPopMenu *)popMenu384 {385 YYTitleButton *titleButton=(YYTitleButton *)self.navigationItem.titleView;386 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_down"] forState:UIControlStateNormal];387 }388 -(void)pop389 {390 YYLog(@"---POP---");391 }392 -(void)friendsearch393 {394 //跳转到one这个子控制器界面395 YYOneViewController *one=[[YYOneViewController alloc]init];396 one.title=@"One";397 //拿到当前控制器398 [self.navigationController pushViewController:one animated:YES];399 400 }401 402 #pragma mark - Table view data source403 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section404 {405 #warning 监听tableView每次显示数据的过程406 //在tableView显示之前,判断有没有数据,如有有数据那么就显示底部视图407 self.footer.hidden=self.statuses.count==0;408 return self.statuses.count;409 }410 411 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath412 {413 static NSString *ID = @"cell";414 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];415 if (!cell) {416 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];417 }418 419 //取出这行对应的微博字典数据,转换为数据模型420 YYStatusModel *status=self.statuses[indexPath.row];421 cell.textLabel.text=status.text;422 cell.detailTextLabel.text=status.user.name;423 NSString *imageUrlStr=status.user.profile_image_url;424 [cell.imageView setImageWithURL:[NSURL URLWithString:imageUrlStr] placeholderImage:[UIImage imageWithName:@"avatar_default_small"]];425 426 return cell;427 }428 429 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath430 {431 //点击cell的时候,跳到下一个界面432 UIViewController *newVc = [[UIViewController alloc] init];433 newVc.view.backgroundColor = [UIColor redColor];434 newVc.title = @"新控制器";435 [self.navigationController pushViewController:newVc animated:YES];436 }437 438 #pragma mark-代理方法439 - (void)scrollViewDidScroll:(UIScrollView *)scrollView440 {441 if (self.statuses.count <= 0 || self.footer.isRefreshing) return;442 443 // 1.差距444 CGFloat delta = scrollView.contentSize.height - scrollView.contentOffset.y;445 // 刚好能完整看到footer的高度446 CGFloat sawFooterH = self.view.height - self.tabBarController.tabBar.height;447 448 // 2.如果能看见整个footer449 if (delta <= (sawFooterH - 0)) {450 // 进入上拉刷新状态451 [self.footer beginRefreshing];452 453 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{454 // 加载更多的微博数据455 [self loadMoreStatuses];456 });457 }458 }459 @end
5.项目分层架构示意图
部分项目文件结构截图
项目分层:
步骤:
(1)新建一个模型类封装请求参数
(2)新建一个模型类封装请求结果(返回结果)
(3)新建一个业务类封装专一的业务
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。