前言
每次写一些东西,总会碰到各种各样的错误.希望把他们整理出来,附上解决的办法.
由于错误实在是太多了,这里就以自己遇到的一系列的坑.碰到了就记录起来.希望帮到大家
简介
话不多说,直接开始吧.楼主最近在写一个简单的旅游app 用到了轮播图 在TableView中异步加载图片的问题.nib和storyboard的问题.frame在AutoLayoutx下错位.分页数据加载等的很多问题
ScrollView + NavigationController ScrolleView显示错位
在我们使用ScrollView的时候,在AutoLayout下你约束好了ScrollView,但是你在ViewController 中指定了ContentSize的大小. 然后设置contentOffSet来展示你的视图
<strong>注意:如果你的视图恰好处于NavigationController中的话,你会发现不管你怎么设置contentOffSet 图片的位置始终不是处于一个理想的状态.你可能发现你的contentOffSet 是正确的,不然你会一直陷进去去调整你的contentOffSet的那个点位置</strong>
解释:只要scrollView是其父视图上的第一个子视图,且navigationBar不隐藏的情况下,添加到scrollView里的视图,都会默认下移64个像素。这就是导致你设置contentOffSet始终无法正确显示的原因
解决:在ViewDidLoad 中加上这行代码
self.automaticallyAdjustsScrollViewInsets = NO; //自动滚动调整
更详细的解释在这里:http://www.cocoachina.com/bbs/read.php?tid-246393.html
TableView的图片异步加载错乱和TableView分页
我们都知道为了提高app流畅度,我们不可能把一些费时的工作(如:获取网络图片)放在主线程中去进行,这就会造成我们的主线程停下来开始执行这些费时的操作,主线程会阻塞.我们最简单的想起来提高app响应速度的就是将这些网络相关的操作放在其他线程去异步的进行.这就有了我们接下来的错误:<strong>UITableView异步加载图片,图片显示错位</strong>
原谅我无法附上图片来帮助大家更好的理解
解释:TableView一次只能显示5行的图片,在所有图片都加载完后,滚动TableView,让隐藏在下面的行显示在屏幕上,而这些行(比如6行)的图像会先显示第1行的图片,然后在显示属于它自己的图片。以此类推,后面的行都会出现这样的问题!! 即使我们在所有行的图片都还没有下载完成的时候,滚动TableView,让第11行、12行等出现在屏幕上,但它们依旧会先显示错误的图片,然后再显示正确的图片。这就是错误原因TableView的重用机制导致
具体的解释:http://blog.csdn.net/xhl916235259/article/details/48898989
解决方法:
- 最简单的方法:把图片的url放入cell中,异步加载完成的时候判断其url是否与cell内的相同,相同的时候再setImage.
细点说你可以自定义cell类,每个cell有自己的url属性.当你加载图片完成的时候,拿出来url和cell的url属性进行对比.虽然cell是可以重用的,但是每个cell都有唯一的url标识.如果两个url相等,这个时候再去设置图片就可以了
- 使用:SDWebImage 直接解决这些问题,不用再关心图片异步等的问题
分页加载
很多时候我们都是和后台程序员一起开发程序.由于数据太多,所以使用了分页的方法去把一个庞大的数据分割成一页一页的.那么我们的TableView如何分页?总是出错?
思路:先简单的说一下思路吧,假设一页数据有10个,那我们的单元格可以设置为11个,最后一个设置为加载更多,使用这个方法去触发一次新的网络请求来获取新的一页的数据.然后再将这些数据添加到我们的数据模型中.
一步步的详细的说:这里以我的app为例
-
首先我们要用一个容器来存放我们获取到的数据(一般都是JSON).我们使用NSMutableArray(因为我们以后还要往后面添加)
@interface SceneryViewController () { NSMutableArray *item; //存放数据的可变的容器 }
我们需要填充模型
-(void)getInformatioin{
self.helper = [[AFNetHelper alloc]init];
NSString *baseURL = DATASOURCEURL;
item = [NSMutableArray arrayWithCapacity:20]; //初始化模型
for(int i = 0;i < page;i++) //page:用于记录当前第几页的一个变量,初始化为1
{
NSString *url = [NSString stringWithFormat:@"%@%d",baseURL,i+1];
NSLog(@"%@",url);
[self.helper modelTransfrom:url block:^(NSString * toJSONString) {
NSError * error;
self.model = [[SceneryModel alloc]initWithString:toJSONString error:&error];
[item addObjectsFromArray:self.model.data];//填充模型,将我们的数据填进去
}];
}
}
3.填充完模型我们需要设置相关的TabelView了
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [item count] + 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.row == item.count)
{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cellbasic" forIndexPath:indexPath];
if (page == 3)
{
cell.textLabel.text = @"没有更多了";
}
else
{
cell.textLabel.text = @"加载更多";
}
return cell;
}
else
{
SceneryCell * cell = [SceneryCell cellForRowInSceneryCell:indexPath tableView:tableView model:item];
return cell;
}
}
这就是我们最熟悉的TableViewDataSource 协议了,我们判断当前行是不是最后一行.最后一行负责加载数据
4.接下来我们点击最后一行来触发加载下一页的数据获取
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(indexPath.row == [item count])
{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cellbasic" forIndexPath:indexPath];
if (page == 3) //卤煮这里的分页而为三页,所以page = 3时什么都不错
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}else
{
cell.textLabel.text=@"loading more …";
[self performSelectorInBackground:@selector(loadMore withObject:nil]; //在后台执行loadmore方法 这就是我们的加载更多
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(@"select %ld now indexpath is :%lu ",(long)indexPath.row,(unsigned long)item.count);
}
}
5.触发网络请求 获取下一页的数据
-(void)loadMore
{
page = page+1;
NSString *baseURL = DATASOURCEURL;
NSString *url = [NSString stringWithFormat:@"%@%d",baseURL,page];
[self.helper modelTransfrom:url block:^(NSString * toJSONString) {
NSError * error;
SceneryModel *moreData = [[SceneryModel alloc]initWithString:toJSONString error:&error];
NSMutableArray * more = moreData.data;
[self performSelectorOnMainThread:@selector(appendTableWith:) withObject:more waitUntilDone:NO];
}];
}
我们在后台进行网络数据的获取,拿到了下一页的数据,接下来要添加到我们的容器中.接下来需要在主线程中去进行
6.数据填充
-(void) appendTableWith:(NSMutableArray *)data
{
for (int i=0;i<[data count];i++) {
[item addObject:[data objectAtIndex:i]];
}
NSMutableArray *insertIndexPaths = [NSMutableArray arrayWithCapacity:10];
for (int ind = 0; ind < [data count]; ind++) {
NSIndexPath *newPath = [NSIndexPath indexPathForRow:[item indexOfObject:[data objectAtIndex:ind]] inSection:0];
[insertIndexPaths addObject:newPath];
}
[self.tableview insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimationFade];
}
我们在填充完了数据之后,还需要为这些数据添加IndexPath ,否则你可能出现数组越界的错误. 所以我们更新完模型之后,为这些数据分配indePath,然后把这些插入到我们的tableView中.这样我们的分页加载就大功告成了
最后AFNetWorking的一些问题
一个老生常谈的错误了:
NSLocalizedDescription=Request failed: unacceptable content-type: text/html}
AFNetworking 默认不支持text/html
在自己的代码处加上这句代码:
manager.responseSerializer.acceptableContentType = [NSSet setWithObject:@"text/html"];setWithObject:@"text/html"];
详细的看这里:http://blog.csdn.net/nyh1006/article/details/25068255