iOS 开发中一些常见的错误(一)

前言

每次写一些东西,总会碰到各种各样的错误.希望把他们整理出来,附上解决的办法.
由于错误实在是太多了,这里就以自己遇到的一系列的坑.碰到了就记录起来.希望帮到大家

简介

话不多说,直接开始吧.楼主最近在写一个简单的旅游app 用到了轮播图 在TableView中异步加载图片的问题.nib和storyboard的问题.frame在AutoLayoutx下错位.分页数据加载等的很多问题

ScrollView + NavigationController ScrolleView显示错位

iOS 开发中一些常见的错误(一)_第1张图片
scrollView图片显示错位

在我们使用ScrollView的时候,在AutoLayout下你约束好了ScrollView,但是你在ViewController 中指定了ContentSize的大小. 然后设置contentOffSet来展示你的视图

注意:如果你的视图恰好处于NavigationController中的话,你会发现不管你怎么设置contentOffSet 图片的位置始终不是处于一个理想的状态.你可能发现你的contentOffSet 是正确的,不然你会一直陷进去去调整你的contentOffSet的那个点位置

解释:只要scrollView是其父视图上的第一个子视图,且navigationBar不隐藏的情况下,添加到scrollView里的视图,都会默认下移64个像素。这就是导致你设置contentOffSet始终无法正确显示的原因

解决:在ViewDidLoad 中加上这行代码

 self.automaticallyAdjustsScrollViewInsets = NO; //自动滚动调整

更详细的解释在这里:http://www.cocoachina.com/bbs/read.php?tid-246393.html

iOS 开发中一些常见的错误(一)_第2张图片
加入代码之后

TableView的图片异步加载错乱和TableView分页

我们都知道为了提高app流畅度,我们不可能把一些费时的工作(如:获取网络图片)放在主线程中去进行,这就会造成我们的主线程停下来开始执行这些费时的操作,主线程会阻塞.我们最简单的想起来提高app响应速度的就是将这些网络相关的操作放在其他线程去异步的进行.这就有了我们接下来的错误:UITableView异步加载图片,图片显示错位

原谅我无法附上图片来帮助大家更好的理解

解释:TableView一次只能显示5行的图片,在所有图片都加载完后,滚动TableView,让隐藏在下面的行显示在屏幕上,而这些行(比如6行)的图像会先显示第1行的图片,然后在显示属于它自己的图片。以此类推,后面的行都会出现这样的问题!! 即使我们在所有行的图片都还没有下载完成的时候,滚动TableView,让第11行、12行等出现在屏幕上,但它们依旧会先显示错误的图片,然后再显示正确的图片。这就是错误原因TableView的重用机制导致

具体的解释:http://blog.csdn.net/xhl916235259/article/details/48898989

解决方法:

  1. 最简单的方法:把图片的url放入cell中,异步加载完成的时候判断其url是否与cell内的相同,相同的时候再setImage.

细点说你可以自定义cell类,每个cell有自己的url属性.当你加载图片完成的时候,拿出来url和cell的url属性进行对比.虽然cell是可以重用的,但是每个cell都有唯一的url标识.如果两个url相等,这个时候再去设置图片就可以了

  1. 使用:SDWebImage 直接解决这些问题,不用再关心图片异步等的问题

分页加载

很多时候我们都是和后台程序员一起开发程序.由于数据太多,所以使用了分页的方法去把一个庞大的数据分割成一页一页的.那么我们的TableView如何分页?总是出错?

思路:先简单的说一下思路吧,假设一页数据有10个,那我们的单元格可以设置为11个,最后一个设置为加载更多,使用这个方法去触发一次新的网络请求来获取新的一页的数据.然后再将这些数据添加到我们的数据模型中.

一步步的详细的说:这里以我的app为例

  1. 首先我们要用一个容器来存放我们获取到的数据(一般都是JSON).我们使用NSMutableArray(因为我们以后还要往后面添加)

     @interface SceneryViewController ()
     {
         NSMutableArray *item; //存放数据的可变的容器
     }
    
  2. 我们需要填充模型

-(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

你可能感兴趣的:(iOS 开发中一些常见的错误(一))