iOS开发项目篇—30下拉刷新 一、网络监控 当应用所处的网络环境不好的时候,获取不到相应的网络数据,考虑到用户对应用的使用体验,有必要对网络的状况进行监听。
在程序启动完的时候,监控网络
YYAppDelegate.m文件代码:
1 // 2 // YYAppDelegate.m 3 // 4 5 #import "YYAppDelegate.h" 6 #import "YYOAuthViewController.h" 7 #import "YYControllerTool.h" 8 #import "YYAccountTool.h" 9 #import "YYAccountModel.h" 10 #import "SDWebImageManager.h" 11 #import "SDImageCache.h" 12 #import "AFNetworking.h" 13 #import "MBProgressHUD+MJ.h" 14 15 16 @implementation YYAppDelegate 17 18 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 19 { 20 21 //1.创建窗口 22 self.window=[[UIWindow alloc]init]; 23 self.window.frame=[UIScreen mainScreen].bounds; 24 25 26 //2.显示窗口(主窗口) 27 [self.window makeKeyAndVisible]; 28 29 //3.设置窗口的根控制器 30 YYAccountModel *account=[YYAccountTool accountModel]; 31 32 if (account) { // 存在成功授权的账号信息 33 [YYControllerTool chooseRootViewController]; 34 }else //没有登陆过 35 { 36 self.window.rootViewController=[[YYOAuthViewController alloc]init]; 37 } 38 39 //4.监控网络状态 40 AFNetworkReachabilityManager *mgr=[AFNetworkReachabilityManager sharedManager]; 41 //当网络状态改变的时候,就会调用 42 [mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { 43 switch (status) { 44 case AFNetworkReachabilityStatusUnknown://未知网络 45 case AFNetworkReachabilityStatusNotReachable://没有网络 46 YYLog(@"没有网络(断网)"); 47 [MBProgressHUD showError:@"网络异常,请检查网络设置!"]; 48 break; 49 case AFNetworkReachabilityStatusReachableViaWWAN://手机自带网络 50 YYLog(@"手机自带网络"); 51 break; 52 case AFNetworkReachabilityStatusReachableViaWiFi://WIFI 53 YYLog(@"WIFI"); 54 break; 55 } 56 }]; 57 //开始监控 58 [mgr startMonitoring]; 59 return YES; 60 } 61 62 63 - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application 64 { 65 // 赶紧清除所有的内存缓存 66 [[SDImageCache sharedImageCache] clearMemory]; 67 68 // 赶紧停止正在进行的图片下载操作 69 [[SDWebImageManager sharedManager] cancelAll]; 70 } 二、下拉刷新数据的简单说明 代码: 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 17 @interface YYHomeTableViewController ()<YYPopMenuDelegate> 18 @property(nonatomic,assign)BOOL down; 19 @property(nonatomic,strong)NSArray *statuses; 20 @end 21 22 @implementation YYHomeTableViewController 23 24 - (void)viewDidLoad 25 { 26 [super viewDidLoad]; 27 28 //设置导航栏内容 29 [self setupNavBar]; 30 31 //加载最新数据 32 [self loadNewStatus]; 33 34 //集成刷新控件 35 [self setupRefresh]; 36 } 37 38 //集成刷新控件 39 -(void)setupRefresh 40 { 41 // 1.添加下拉刷新控件 42 UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; 43 [self.tableView addSubview:refreshControl]; 44 45 [self loadNewStatus]; 46 } 47 48 /**加载最新微博数据*/ 49 -(void)loadNewStatus 50 { 51 //1.获得请求管理者 52 AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; 53 54 //2.封装请求参数 55 56 NSMutableDictionary *params=[NSMutableDictionary dictionary]; 57 params[@"access_token"] =[YYAccountTool accountModel].access_token; 58 //设置请求返回3天数据 59 params[@"count"]=@12; 60 61 62 //3.发送Post请求 63 // url:https://api.weibo.com/2/statuses/home_timeline.json 64 [mgr GET:@"https://api.weibo.com/2/statuses/home_timeline.json" parameters:params success:^(AFHTTPRequestOperation *operation, NSDictionary*accountDict) { 65 66 self.statuses=accountDict[@"statuses"]; 67 68 // 微博字典 -- 数组 69 NSArray *statusDictArray = accountDict[@"statuses"]; 70 71 //微博字典数组---》微博模型数组 72 self.statuses=[YYStatusModel objectArrayWithKeyValuesArray:statusDictArray]; 73 74 //重新刷新表格 75 [self.tableView reloadData]; 76 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 77 YYLog(@"请求失败"); 78 }]; 79 80 } 81 /**设置导航栏内容*/ 82 -(void)setupNavBar 83 { 84 self.navigationItem.leftBarButtonItem=[UIBarButtonItem itemWithImageName:@"navigationbar_friendsearch" highImageName:@"navigationbar_friendsearch_highlighted" target:self action:@selector(friendsearch)]; 85 self.navigationItem.rightBarButtonItem=[UIBarButtonItem itemWithImageName:@"navigationbar_pop" highImageName:@"navigationbar_pop_highlighted" target:self action:@selector(pop)]; 86 87 //设置导航栏按钮 88 YYTitleButton *titleButton=[[YYTitleButton alloc]init]; 89 //设置文字 90 [titleButton setTitle:@"首页" forState:UIControlStateNormal]; 91 //设置图标 92 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_down"] forState:UIControlStateNormal]; 93 //设置背景 94 [titleButton setBackgroundImage:[UIImage resizedImage:@"navigationbar_filter_background_highlighted"] forState:UIControlStateHighlighted]; 95 96 //设置尺寸 97 titleButton.width=100; 98 titleButton.height=35; 99 //监听按钮的点击事件 100 [titleButton addTarget:self action:@selector(titleButtonClick:) forControlEvents:UIControlEventTouchUpInside]; 101 self.navigationItem.titleView=titleButton; 102 } 103 -(void)titleButtonClick:(UIButton *)titleButton 104 { 105 106 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_up"] forState:UIControlStateNormal]; 107 108 UITableView *tableView=[[UITableView alloc]init]; 109 [tableView setBackgroundColor:[UIColor yellowColor]]; 110 YYPopMenu *menu=[YYPopMenu popMenuWithContentView:tableView]; 111 [menu showInRect:CGRectMake(60, 55, 200, 200)]; 112 menu.dimBackground=YES; 113 114 menu.arrowPosition=YYPopMenuArrowPositionRight; 115 menu.delegate=self; 116 } 117 118 119 #pragma mark-YYPopMenuDelegate 120 //弹出菜单 121 -(void)popMenuDidDismissed:(YYPopMenu *)popMenu 122 { 123 YYTitleButton *titleButton=(YYTitleButton *)self.navigationItem.titleView; 124 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_down"] forState:UIControlStateNormal]; 125 } 126 -(void)pop 127 { 128 YYLog(@"---POP---"); 129 } 130 -(void)friendsearch 131 { 132 //跳转到one这个子控制器界面 133 YYOneViewController *one=[[YYOneViewController alloc]init]; 134 one.title=@"One"; 135 //拿到当前控制器 136 [self.navigationController pushViewController:one animated:YES]; 137 138 } 139 140 #pragma mark - Table view data source 141 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 142 { 143 return self.statuses.count; 144 } 145 146 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 147 { 148 static NSString *ID = @"cell"; 149 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 150 if (!cell) { 151 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; 152 } 153 154 //取出这行对应的微博字典数据,转换为数据模型 155 YYStatusModel *status=self.statuses[indexPath.row]; 156 cell.textLabel.text=status.text; 157 cell.detailTextLabel.text=status.user.name; 158 NSString *imageUrlStr=status.user.profile_image_url; 159 [cell.imageView setImageWithURL:[NSURL URLWithString:imageUrlStr] placeholderImage:[UIImage imageWithName:@"avatar_default_small"]]; 160 161 return cell; 162 } 163 164 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 165 { 166 //点击cell的时候,跳到下一个界面 167 UIViewController *newVc = [[UIViewController alloc] init]; 168 newVc.view.backgroundColor = [UIColor redColor]; 169 newVc.title = @"新控制器"; 170 [self.navigationController pushViewController:newVc animated:YES]; 171 } 172 173 @end
实现效果:
说明:前者为ios7中得效果。后者为ios6中得效果。 提示:不能直接调用“加载最新微博数据”这个方法,因为如果调用这个方法,那么会重新发送请求给服务器,服务器接受到数据后会直接覆盖以前数组中得数据。
三、下拉刷新的完善 1.关于请求参数 since_id:返回比这个值更大的微博。 提示:id在数据库中通常是自动增长的。 关于id的网络请求处理: 1 //2.封装请求参数 2 3 NSMutableDictionary *params=[NSMutableDictionary dictionary]; 4 params[@"access_token"] =[YYAccountTool accountModel].access_token; 5 // since_id false int64 若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0。 6 //取出当前微博模型中的第一条数据,获取第一条数据的id 7 //不要使用self.statuses[0],这样会产生数组越界问题 8 YYStatusModel *firstStatus=[self.statuses firstObject]; 9 if (firstStatus) { 10 params[@"since_id"]=firstStatus.idstr; 11 } 说明:如果是直接刷新的话,那么每次获取的数据会直接覆盖掉以前的数据,比如现在最大的id值为10,刷新数据,如果只有两条新的数据,那么微博模型中就只有11,12数据。 解决:更改数组为可变数组,然后对刷新获取的数据进行拼接。 插入: (1) [self.statuses insertObject:newStatuses atIndex:0];这种方式是把整个数组作为第一个元素插入到原来的数组中,即数组中的第一个元素是数组。 (2)[self.statuses insertObjects:newStatuses atIndexes:0];这种方式是把数组中的元素一次插入到数组中。 实现代码: 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 17 @interface YYHomeTableViewController ()<YYPopMenuDelegate> 18 @property(nonatomic,assign)BOOL down; 19 @property(nonatomic,strong)NSMutableArray *statuses; 20 @end 21 22 @implementation YYHomeTableViewController 23 24 #pragma mark- 懒加载 25 -(NSMutableArray *)statuses 26 { 27 if (_statuses==nil) { 28 _statuses=[NSMutableArray array]; 29 } 30 return _statuses; 31 } 32 - (void)viewDidLoad 33 { 34 [super viewDidLoad]; 35 36 //设置导航栏内容 37 [self setupNavBar]; 38 39 // //加载最新数据 40 // [self loadNewStatus]; 41 42 //集成刷新控件 43 [self setupRefresh]; 44 } 45 46 //集成刷新控件 47 -(void)setupRefresh 48 { 49 // 1.添加下拉刷新控件 50 UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init]; 51 [self.tableView addSubview:refreshControl]; 52 53 [refreshControl addTarget:self action:(@selector(refreshControlStateChange:)) forControlEvents:UIControlEventValueChanged]; 54 // [self loadNewStatus]; 55 } 56 57 /** 58 * 当下拉刷新控件进入刷新状态(转圈圈)的时候会自动调用 59 */ 60 -(void)refreshControlStateChange:(UIRefreshControl *)refreshControl 61 { 62 //1.获得请求管理者 63 AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager]; 64 65 //2.封装请求参数 66 67 NSMutableDictionary *params=[NSMutableDictionary dictionary]; 68 params[@"access_token"] =[YYAccountTool accountModel].access_token; 69 70 // since_id false int64 若指定此参数,则返回ID比since_id大的微博(即比since_id时间晚的微博),默认为0。 71 //取出当前微博模型中的第一条数据,获取第一条数据的id 72 //不要使用self.statuses[0],这样会产生数组越界问题 73 YYStatusModel *firstStatus=[self.statuses firstObject]; 74 if (firstStatus) { 75 params[@"since_id"]=firstStatus.idstr; 76 } 77 78 //设置请求返回的数据 79 // params[@"count"]=@12; 80 81 82 //3.发送Get请求 83 [mgr GET:@"https://api.weibo.com/2/statuses/home_timeline.json" parameters:params success:^(AFHTTPRequestOperation *operation, NSDictionary*accountDict) { 84 85 // self.statuses=accountDict[@"statuses"]; 86 87 // 微博字典 -- 数组 88 NSArray *statusDictArray = accountDict[@"statuses"]; 89 90 //微博字典数组---》微博模型数组 91 NSArray *newStatuses =[YYStatusModel objectArrayWithKeyValuesArray:statusDictArray]; 92 93 //把新数据添加到旧数据的前面 94 NSRange range=NSMakeRange(0, newStatuses.count); 95 NSIndexSet *indexSet=[NSIndexSet indexSetWithIndexesInRange:range]; 96 [self.statuses insertObjects:newStatuses atIndexes:indexSet]; 97 YYLog(@"刷新了--%d条新数据",newStatuses.count); 98 99 //重新刷新表格 100 [self.tableView reloadData]; 101 //让刷新控件停止刷新(回复默认的状态) 102 [refreshControl endRefreshing]; 103 104 } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 105 YYLog(@"请求失败"); 106 //让刷新控件停止刷新(回复默认的状态) 107 [refreshControl endRefreshing]; 108 }]; 109 110 } 111 112 113 /**设置导航栏内容*/ 114 -(void)setupNavBar 115 { 116 self.navigationItem.leftBarButtonItem=[UIBarButtonItem itemWithImageName:@"navigationbar_friendsearch" highImageName:@"navigationbar_friendsearch_highlighted" target:self action:@selector(friendsearch)]; 117 self.navigationItem.rightBarButtonItem=[UIBarButtonItem itemWithImageName:@"navigationbar_pop" highImageName:@"navigationbar_pop_highlighted" target:self action:@selector(pop)]; 118 119 //设置导航栏按钮 120 YYTitleButton *titleButton=[[YYTitleButton alloc]init]; 121 //设置文字 122 [titleButton setTitle:@"首页" forState:UIControlStateNormal]; 123 //设置图标 124 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_down"] forState:UIControlStateNormal]; 125 //设置背景 126 [titleButton setBackgroundImage:[UIImage resizedImage:@"navigationbar_filter_background_highlighted"] forState:UIControlStateHighlighted]; 127 128 //设置尺寸 129 titleButton.width=100; 130 titleButton.height=35; 131 //监听按钮的点击事件 132 [titleButton addTarget:self action:@selector(titleButtonClick:) forControlEvents:UIControlEventTouchUpInside]; 133 self.navigationItem.titleView=titleButton; 134 } 135 -(void)titleButtonClick:(UIButton *)titleButton 136 { 137 138 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_up"] forState:UIControlStateNormal]; 139 140 UITableView *tableView=[[UITableView alloc]init]; 141 [tableView setBackgroundColor:[UIColor yellowColor]]; 142 YYPopMenu *menu=[YYPopMenu popMenuWithContentView:tableView]; 143 [menu showInRect:CGRectMake(60, 55, 200, 200)]; 144 menu.dimBackground=YES; 145 146 menu.arrowPosition=YYPopMenuArrowPositionRight; 147 menu.delegate=self; 148 } 149 150 151 #pragma mark-YYPopMenuDelegate 152 //弹出菜单 153 -(void)popMenuDidDismissed:(YYPopMenu *)popMenu 154 { 155 YYTitleButton *titleButton=(YYTitleButton *)self.navigationItem.titleView; 156 [titleButton setImage:[UIImage imageWithName:@"navigationbar_arrow_down"] forState:UIControlStateNormal]; 157 } 158 -(void)pop 159 { 160 YYLog(@"---POP---"); 161 } 162 -(void)friendsearch 163 { 164 //跳转到one这个子控制器界面 165 YYOneViewController *one=[[YYOneViewController alloc]init]; 166 one.title=@"One"; 167 //拿到当前控制器 168 [self.navigationController pushViewController:one animated:YES]; 169 170 } 171 172 #pragma mark - Table view data source 173 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 174 { 175 return self.statuses.count; 176 } 177 178 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 179 { 180 static NSString *ID = @"cell"; 181 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; 182 if (!cell) { 183 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID]; 184 } 185 186 //取出这行对应的微博字典数据,转换为数据模型 187 YYStatusModel *status=self.statuses[indexPath.row]; 188 cell.textLabel.text=status.text; 189 cell.detailTextLabel.text=status.user.name; 190 NSString *imageUrlStr=status.user.profile_image_url; 191 [cell.imageView setImageWithURL:[NSURL URLWithString:imageUrlStr] placeholderImage:[UIImage imageWithName:@"avatar_default_small"]]; 192 193 return cell; 194 } 195 196 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 197 { 198 //点击cell的时候,跳到下一个界面 199 UIViewController *newVc = [[UIViewController alloc] init]; 200 newVc.view.backgroundColor = [UIColor redColor]; 201 newVc.title = @"新控制器"; 202 [self.navigationController pushViewController:newVc animated:YES]; 203 } 204 205 @end
重要错误: 错误提示:数据插入到了一个不可变对象中。 提示:在拿到刷新的数据后,应该让刷新控件停止刷新。 说明:刷新控件,在ios6以后可以使用。 注意:账号并没有通过新浪的审核,所以调用接口的频率是有限制的。 执行显示: 打印查看: |
|