[BS-23] AFN网络请求上拉/下拉刷新的细节问题总结
上拉/下拉刷新的细节问题总结
1.如果导航栏有透明色,则也需要设置header自动改变透明度
self.tableView.mj_header.automaticallyChangeAlpha = YES; //允许自动改变透明度
2. 下拉刷新必须手动调用[self.tableView.mj_header beginRefreshing];才开始刷新,下拉刷新只要用户滚动到最下方,自动开始加载更多。
3. 上拉刷新通常用的是用MJRefreshAutoNormalFooter,该控件总是紧贴最后一条数据下方。故第一次进入界面时,还没有数据,footer就会显示在最顶部,比较难看。解决的办法:因为第一次进入tableView,不管有没有从网络加载数据,它都会先调用数据源方法numberOfRowsInSection,且以后每次reloadData也会调用该方法。所以在该方法中控制footer是否隐藏最合适。
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
//第一次进来或者每次reloadData否会调一次该方法,在此控制footer是否隐藏
self.tableView.mj_footer.hidden = (self.topics.count == );
return self.topics.count;
}
4.
在上拉刷新中处理数据采用如下方法: //字典-》模型
self.topics = [WZTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];
分析机理:
如果第二次下拉,返回的数据会将整个self.topics数据覆盖掉,相当于先清空容器中数据,然后再向容器中加入新数据。如果采用self.topics=nil;这样的方式清空,堆中的原来的模型数组(容器)因无强引用就会销毁。然后再调用 [self.topics addObject: dict];因self.topics此前为nil,就会懒加载重新开辟一块内存用来充当容器。这样将原来的罐子摔烂,买个新罐子装东西的做法实属浪费,这样加大系统的负荷,效率没有前者高。
5.通过thisPage = self.page+1来加载服务器数据的细节控制(红色为核心控制代码)
#import "WZWordTableViewController.h"
#import <AFNetworking.h>
#import <UIImageView+WebCache.h> //分类
#import "WZTopic.h"
#import <MJExtension.h>
#import <SVProgressHUD.h>
#import <MJRefresh.h> @interface WZWordTableViewController ()
//服务器返回的值
@property (strong,nonatomic) NSNumber *count; //服务器返回的总数据条数
@property (strong,nonatomic) NSMutableArray *topics; //模型数组 //请求参数
@property (assign,nonatomic) NSInteger page;//发送请求时使用的页数,每次加载下一页,让该值page +1 //保存本次发送请求的参数,用于控制只处理最后一次请求的参数(如下拉不成功,又去上拉,上拉的数据显示出来后,下拉的数据才回来,此时会将表中已显示数据突然清空,只显示第一页数据)
@property (strong,nonatomic) NSDictionary *newestParams; @end @implementation WZWordTableViewController - (void)viewDidLoad {
[super viewDidLoad]; self.tableView.rowHeight = ; //设置下拉和上拉刷新
[self setupMJRefresh]; } //懒加载topics的get方法,第一次调self.topics时,分配空间和初始化topics数组
- (NSMutableArray *)topics { if (!_topics) {
_topics = [[NSMutableArray alloc]init];
} return _topics;
} /** 设置下拉和上拉刷新 */
- (void)setupMJRefresh { //设置header
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewTopics)];
//允许自动改变透明度
self.tableView.mj_header.automaticallyChangeAlpha = YES;
//header开始刷新
[self.tableView.mj_header beginRefreshing]; //设置footer,用户滑到最下边就会自动启用footer刷新,故不用写开始刷新的代码
self.tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreTopics)]; //self.tableView.mj_footer.hidden = YES;//数据尚未返回,或者加载失败footer都会跑到最顶部。//改成在numberOfRows方法中控制了
} /** 加载新的帖子 */
- (void)loadNewTopics { //下拉先停止footer刷新
[self.tableView.mj_footer endRefreshing]; //每次下拉让页码都回归到第0页
//self.page = 0; (不在此设置,如多次下拉加载不成功,在回到底部上拉,此时页码已变为0,之前可能已是第5页了,后面又接着1,2,3...出现重复加载) //设置参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"list";
NSInteger thisPage = 0; //第一次请求发送0还是1由看接口文档,此处不能直接写self.page=0; 每次请求成功后,才能将当前thisPage保存进self.page中,供下次请求使用。
params[@"page"] = @(thisPage); //此处不能写为@(self.page), self.newestParams = params; //self.newestParams是全局的,永远只存储最后一次请求的参数,之前的请求参数都会被最后一次覆盖掉。 //发送请求
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { //如果不是用户最近一次发送的请求,就不处理,直接return整个AFN方法,后面failure也不会执行
if(params != self.newestParams) return; //能来到这说明本次加载成功,此时将本次页码保存在self.page中,以便下次加载使用。
self.page = thisPage; //解析服务器返回数据
NSDictionary *infoDict = responseObject[@"info"];
self.count = infoDict[@"count"]; //总帖子数可能随时会增加,每次请求都重新存储一遍 //字典-》模型(如果第二次下拉,返回的数据会将整个self.topics数据覆盖掉,相当于先清空,再加载)
self.topics = [WZTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];//此句会在内部通过KVC将responseObject[@"list"]这个包含20个字典的数组转为包含20个topic模型的数组 [self.tableView reloadData];//刷新表格才会显示数据 //返回数据了就停止刷新
[self.tableView.mj_header endRefreshing]; //让footer显示出来(第一次让footer隐藏了)
//self.tableView.mj_footer.hidden = NO; //改成在numberOfRows方法中控制了 } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { //提示用户加载失败
[SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeBlack];//第一次使用时设置就可以
[SVProgressHUD showErrorWithStatus:@"加载失败"]; //停止header刷新(第一次加载失败,footer就不会显示出来,不用停止footer)
[self.tableView.mj_header endRefreshing]; }]; } /** 加载更多帖子 */
- (void)loadMoreTopics { //上拉先停止header刷新
[self.tableView.mj_header endRefreshing]; //设置参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"list";
NSInteger thisPage = (self.page+1); //此处不能写成++self.page,会改变self.page的值。如果加载不成功,还得去--。每次请求成功后,才能将当前thisPage保存进self.page中,供下次请求使用。
params[@"page"] = @(thisPage);
self.newestParams = params; //self.newestParams是全局的,永远只存储最后一次请求的参数,之前的请求参数都会被最后一次覆盖掉。 //发送请求
[[AFHTTPSessionManager manager] GET:@"http://api.budejie.com/api/api_open.php" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { //如果不是用户最近一次发送的请求,就不处理,直接return整个AFN方法,后面failure也不会执行
if(params != self.newestParams) return; //能来到这说明本次加载成功,此时将本次页码保存在self.page中,以便下次加载使用。
self.page = thisPage; //解析服务器返回数据
NSDictionary *infoDict = responseObject[@"info"];
self.count = infoDict[@"count"]; //总帖子数可能随时会增加,每次请求都重新存储一遍 //字典-》模型
NSArray *array = [WZTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];//此句会在内部通过KVC将responseObject[@"list"]这个包含20个字典的数组转为包含20个topic模型的数组 //添加模型到可变数字topics中
[self.topics addObjectsFromArray:array];//把第二次返回的数据加到数组中 [self.tableView reloadData];//刷新表格才会显示数据 } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { //提示用户加载失败
//[SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeBlack];//只需要设置一次就ok
[SVProgressHUD showErrorWithStatus:@"加载失败"]; //加载失败了footer停止刷新
[self.tableView.mj_footer endRefreshing]; }];
} #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { //判断footer是否隐藏,判断footer停止刷新时显示"加载更多"还是"全部数据已加载完成"
[self checkFooterStatus]; return self.topics.count;
} //判断footer是否隐藏,判断footer停止刷新时显示"加载更多"还是"全部数据已加载完成"
-(void)checkFooterStatus {
//第一次进来或者每次reloadData否会调一次该方法,在此控制footer是否隐藏
self.tableView.mj_footer.hidden = (self.topics.count == ); //用户滑到最下边就会自动启用footer刷新,现在数据回来了要footer停止刷新
if (self.topics.count == self.count.unsignedIntegerValue) {
[self.tableView.mj_footer endRefreshingWithNoMoreData];
} else {
[self.tableView.mj_footer endRefreshing];
}
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//创建cell
static NSString *const ID = @"Word";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
} //获取模型
WZTopic *topic = self.topics[indexPath.row]; //设置数据
cell.textLabel.text = topic.name;
cell.detailTextLabel.text = topic.text;
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:topic.profile_image] placeholderImage:[UIImage imageNamed:@"defaultUserIcon"]]; //返回cell
return cell;
} @end
6.通过最大的id来加载服务器数据的细节控制(删掉恶心的page控制代码,直接发给服务器最大id即可加载下一页,红色为核心控制代码)
#import "WZWordTableViewController.h"
#import <AFNetworking.h>
#import <UIImageView+WebCache.h> //分类
#import "WZTopic.h"
#import <MJExtension.h>
#import <SVProgressHUD.h>
#import <MJRefresh.h> @interface WZWordTableViewController ()
//服务器返回的值
@property (strong,nonatomic) NSNumber *count; //服务器返回的总数据条数
@property (strong,nonatomic) NSMutableArray *topics; //模型数组 //保存本次发送请求的参数,用于控制只处理最后一次请求的参数(如下拉不成功,又去上拉,上拉的数据显示出来后,下拉的数据才回来,此时会将表中已显示数据突然清空,只显示第一页数据)
@property (strong,nonatomic) NSDictionary *newestParams; @end @implementation WZWordTableViewController - (void)viewDidLoad {
[super viewDidLoad]; self.tableView.rowHeight = ; //设置下拉和上拉刷新
[self setupMJRefresh]; } //懒加载topics的get方法,第一次调self.topics时,分配空间和初始化topics数组
- (NSMutableArray *)topics { if (!_topics) {
_topics = [[NSMutableArray alloc]init];
} return _topics;
} /** 设置下拉和上拉刷新 */
- (void)setupMJRefresh { //设置header
self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewTopics)];
//允许自动改变透明度
self.tableView.mj_header.automaticallyChangeAlpha = YES;
//header开始刷新
[self.tableView.mj_header beginRefreshing]; //设置footer,用户滑到最下边就会自动启用footer刷新,故不用写开始刷新的代码
self.tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreTopics)]; //self.tableView.mj_footer.hidden = YES;//数据尚未返回,或者加载失败footer都会跑到最顶部。//改成在numberOfRows方法中控制了
} /** 加载新的帖子 */
- (void)loadNewTopics { //下拉先停止footer刷新
[self.tableView.mj_footer endRefreshing]; //设置参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"list";
//params[@"maxtime"] = @""; //不设置maxtime默认加载第一页
self.newestParams = params; //self.newestParams是全局的,永远只存储最后一次请求的参数,之前的请求参数都会被最后一次覆盖掉。 //发送请求
[[AFHTTPSessionManager manager] GET:@"http://api.com/api/api_open.php" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { //如果不是用户最近一次发送的请求,就不处理,直接return整个AFN方法,后面failure也不会执行
if(params != self.newestParams) return; //解析服务器返回数据
NSDictionary *infoDict = responseObject[@"info"];
self.count = infoDict[@"count"]; //总帖子数可能随时会增加,每次请求都重新存储一遍
self.maxtime = infoDict[@"maxtime"]; //下次加载需使用 //字典-》模型(如果第二次下拉,返回的数据会将整个self.topics数据覆盖掉,相当于先清空,再加载)
self.topics = [WZTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];//此句会在内部通过KVC将responseObject[@"list"]这个包含20个字典的数组转为包含20个topic模型的数组 [self.tableView reloadData];//刷新表格才会显示数据 //返回数据了就停止刷新
[self.tableView.mj_header endRefreshing]; //让footer显示出来(第一次让footer隐藏了)
//self.tableView.mj_footer.hidden = NO; //改成在numberOfRows方法中控制了 } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { //提示用户加载失败
[SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeBlack];//第一次使用时设置就可以
[SVProgressHUD showErrorWithStatus:@"加载失败"]; //停止header刷新(第一次加载失败,footer就不会显示出来,不用停止footer)
[self.tableView.mj_header endRefreshing]; }]; } /** 加载更多帖子 */
- (void)loadMoreTopics { //上拉先停止header刷新
[self.tableView.mj_header endRefreshing]; //设置参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"a"] = @"list";
params[@"maxtime"] = self.maxtime; //由上一次返回的数据提供
self.newestParams = params; //self.newestParams是全局的,永远只存储最后一次请求的参数,之前的请求参数都会被最后一次覆盖掉。 //发送请求
[[AFHTTPSessionManager manager] GET:@"http://api.com/api/api_open.php" parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { //如果不是用户最近一次发送的请求,就不处理,直接return整个AFN方法,后面failure也不会执行
if(params != self.newestParams) return; //解析服务器返回数据
NSDictionary *infoDict = responseObject[@"info"];
self.count = infoDict[@"count"]; //总帖子数可能随时会增加,每次请求都重新存储一遍
self.maxtime = infoDict[@"maxtime"]; //下次加载需使用 //字典-》模型
NSArray *array = [WZTopic mj_objectArrayWithKeyValuesArray:responseObject[@"list"]];//此句会在内部通过KVC将responseObject[@"list"]这个包含20个字典的数组转为包含20个topic模型的数组 //添加模型到可变数字topics中
[self.topics addObjectsFromArray:array];//把第二次返回的数据加到数组中 [self.tableView reloadData];//刷新表格才会显示数据 } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { //提示用户加载失败
//[SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeBlack];//只需要设置一次就ok
[SVProgressHUD showErrorWithStatus:@"加载失败"]; //加载失败了footer停止刷新
[self.tableView.mj_footer endRefreshing]; }];
} #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { //判断footer是否隐藏,判断footer停止刷新时显示"加载更多"还是"全部数据已加载完成"
[self checkFooterStatus]; return self.topics.count;
} //判断footer是否隐藏,判断footer停止刷新时显示"加载更多"还是"全部数据已加载完成"
-(void)checkFooterStatus {
//第一次进来或者每次reloadData否会调一次该方法,在此控制footer是否隐藏
self.tableView.mj_footer.hidden = (self.topics.count == ); //用户滑到最下边就会自动启用footer刷新,现在数据回来了要footer停止刷新
if (self.topics.count == self.count.unsignedIntegerValue) {
[self.tableView.mj_footer endRefreshingWithNoMoreData];
} else {
[self.tableView.mj_footer endRefreshing];
}
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//创建cell
static NSString *const ID = @"Word";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
} //获取模型
WZTopic *topic = self.topics[indexPath.row]; //设置数据
cell.textLabel.text = topic.name;
cell.detailTextLabel.text = topic.text;
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:topic.profile_image] placeholderImage:[UIImage imageNamed:@"defaultUserIcon"]]; //返回cell
return cell;
} @end
文章系作者原创,转载请注明出处:http://www.cnblogs.com/stevenwuzheng/p/5506286.html
如有错误,欢迎随时指正!
[BS-23] AFN网络请求上拉/下拉刷新的细节问题总结的更多相关文章
- Swiper 判断上滑下拉操作
onTouchMove: function(swiper){ //手动滑动中触发//判断上滑下拉var i = mySwiper.translate;setTimeout(function() {va ...
- ios position:fixed 上滑下拉抖动
ios position:fixed 上滑下拉抖动 最近呢遇到一个ios的兼容问题,界面是需要一个头底部的固定的效果,用的position:fixed定位布局,写完测试发现安卓手机正常的,按时ios上 ...
- ASI与AFN网络请求的的比较
对比 ASI AFN 更新状态 2012年10月份,已经停止更新 持续更新中,目前已更新至3.0版 介绍 ASI的直接操作对象ASIHTTPRequest,是一个实现了了NSCopying协议的NSO ...
- 原生网络请求以及AFN网络请求/异步下载
这里对网络请求方式做一个总结. 原生方式同步GET请求: NSString *urlStr = @"http://apis.juhe.cn/mobile/get?phone=13429667 ...
- jsp页面上的下拉框案例(Struts2)
<s:select></s:select>包含的属性有:list="" :name="" :value="" ...
- 浅谈对MJRefresh(上)下拉刷新控件的理解
MJRefresh GitHub地址:https://github.com/CoderMJLee/MJRefresh 利用业余时间研究了一下iOS的开发,发现OC特定的语法方式吸引了我,而且iOS开发 ...
- 160823、ionic上拉/下拉更新数据
<!DOCTYPE html> <html ng-app="myApp"> <head> <meta charset="UTF- ...
- js实现页面的上滑下拉功能
这两天做项目,用到了上滑和下拉的功能,主要是通过监听touchmove,touchstart,touchend三个事件去判断页面上滑状态还是下拉状态. 同时加一个知识点:有时在监听时会报错,这个错是这 ...
- SDI在自定义的工具栏上添加下拉控件
0.首先到自己的工具条上新建一个控件,并命名新ID 1.拷贝FlatComboBox.h和FlatComboBox.cpp到工程目录下 2.建立新类 class CTrackerToolBar : p ...
随机推荐
- Linux 随笔1
使用fork()系统调用产生的子进程对父进程中数据的修改不会影响到父进程,因为fork()采用的是写时复制机制,就是在fork产生的子进程没有修改父进程的值时,父子进程共享同一块内存,包括栈区.当子进 ...
- 9. Add the Block Storage service
Block Storage Server: 1. sudo apt-get install python-mysqldb 2. sudo apt-get install lvm2 3. 创建存 ...
- ubuntu安装chrome
1.在Google chrome上面下载Chrome浏览器.选择正确的版本,我电脑是64位的所以选择的是[64 bit .deb (适用于 Debian/Ubuntu)]. google-Chrome ...
- laravel url() 和 asset() 的区别
asset()方法用于引入 CSS/JavaScript/images 等文件,文件必须存放在public文件目录下.url()方法生成一个完整的网址.
- Memcached 笔记与总结(1)Linux(CentOS 6.6) 和 Windows(7)下安装与配置 Memcached (1.4.24)与 Memcached 基础命令
Memcached 官方网站:http://memcached.org/ 官网对其的描述是: What is Memcached? Free & open source, high-perfo ...
- 【CEDEC 2015】【夏日课堂】制作事宜技术篇,新手职员挑战VR Demo开发的真相
日文原文地址 http://www.4gamer.net/games/277/G027751/20150829002/ PS:CEDEC 2015的PPT有些要到10月才有下载,目前的都是记者照片修图 ...
- 提高Vector容器的删除效率
vector容器是类似与一个线性数组,索引效率高,插入,删除的效率很低,需要遍历数据列表,一般情况下vector的删除操作由一下函数完成: iterator erase(iterator positi ...
- Bootstrap页面布局20 - BS缩略图
<div class='container-fluid'> <h2 class='page-header'>Bootstrap 缩略图</h2> <ul cl ...
- 【转载】wireshark抓包
两种过滤器 捕捉过滤器:用于决定将什么样的信息记录在捕捉结果中.需要在开始捕捉前设置显示过滤器:在捕捉结果中进行详细查找.他们可以在得到捕捉结果后随意修改 1.捕捉过滤器 语法实例: tcp ds ...
- Centos下安装Scrapy
Scrapy是一个开源的机遇twisted框架的python的单机爬虫,该爬虫实际上包含大多数网页抓取的工具包,用于爬虫下载端以及抽取端. 安装环境: centos5.4 python2.7.3 安装 ...