Ios Tableview滚动崩溃应用程序

Ios Tableview滚动崩溃应用程序,ios,iphone,objective-c,ipad,nsthread,Ios,Iphone,Objective C,Ipad,Nsthread,我正在开发一个iPhone应用程序,我在后台从服务器下载图像 这是我的申请表 当我点击按钮1时,我正在从服务器获取5个数据,也就是图像,当用户向上滚动时获取数据后,我再次从服务器获取新的5个数据,当用户向上滚动时,我正在从服务器获取新的5个数据,依此类推 在为按钮1获取数据时,如果我点击按钮2我将取消先前的按钮1线程,并为按钮2获取新的5个数据,然后再次滚动它,获取与按钮1相同的新的5个数据 但在重新加载tableview一段时间后,我的应用程序会崩溃并显示: 由于未捕获的异常“NSRange

我正在开发一个iPhone应用程序,我在后台从服务器下载图像

这是我的申请表

当我点击
按钮1
时,我正在从服务器获取5个数据,也就是图像,当用户向上滚动时获取数据后,我再次从服务器获取新的5个数据,当用户向上滚动时,我正在从服务器获取新的5个数据,依此类推

在为
按钮1
获取数据时,如果我点击
按钮2
我将取消先前的
按钮1
线程,并为
按钮2
获取新的5个数据,然后再次滚动它,获取与按钮1相同的新的5个数据

但在重新加载tableview一段时间后,我的应用程序会崩溃并显示: 由于未捕获的异常“NSRangeException”而终止应用程序,原因:'-[\uu NSArrayM objectAtIndex:]:索引28超出范围[0..4]

以下是我的代码片段:

- (void)viewDidLoad
{
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        [self fetchDataForButton1]; 

        dispatch_async(dispatch_get_main_queue(), ^(void) {


                [tableView reloadData];


        });
    });

}


- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
 if(it is last row then fetch new 5 data)
 {
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

                        //Code runs on background thread
                        [self LoadMoreData];

                        dispatch_async(dispatch_get_main_queue(), ^(void) {

                            //Code here is run on the main thread
                            [_tblList reloadData];

                        });
                    });


      }else{
              dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

                                [self beginBackgroundFetchTask];

                               [self downloadImage_3:indexPath];

                                [self endBackgroundFetchTask];
                            });
      } 

}


-(void)downloadImage_3:(NSIndexPath *)path{


        UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:ImagePath]]];

        if (img) {
            [dicImages_msg setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:@"Merchant_SmallImage"]];
        }

        [_tblList performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];


}

- (void) beginBackgroundFetchTask
{
   self.backgroundFetchTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self endBackgroundFetchTask];
    }];
}

- (void) endBackgroundFetchTask
{
    [[UIApplication sharedApplication] endBackgroundTask: self.backgroundFetchTask];
    self.backgroundFetchTask = UIBackgroundTaskInvalid;
    NSLog(@"ended BackgroundFetchTask");
}

-(void)LoadMoreData
{
   //Fetches new 5 data from server...
}

使用SDWebImage从服务器获取图像。

根据您的日志数组只有5个计数,您正在按照
indexpath.row
获取数据,在这种崩溃情况下为28。因此,您可能正在根据新数组调整单元格indexpath行,该数组在滚动时一次又一次地获取数据,但重复5

只需放置一个断点并检查是否正在重置计数为[0 4]的indexpath行

更新:

[[NSThread currentThread]  populateDataInBackground];

这是因为从服务器加载图像需要时间,而单元在分配时不会获得任何数据

您需要为它实现延迟加载


这是一个很好的教程。

禁用用户交互,然后转到表格顶部:

 [TableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
然后打电话:

 [TableView reloadData];
然后启用用户交互。 希望能解决问题

试试这个

1) 用于从服务器获取图像

2) 使用该功能获取下5个数据


这将有助于在后台获取数据。

我不会从
cellforrowatinexpath
方法获取这样的数据。用于显示单元格的

而是这样做:

  • 列出您的原始数据
  • 当用户滚动过最后一个单元格时,显示一个显示加载符号的页脚
  • 在页脚显示加载符号的同时,然后调用
    fetchLoadData
    方法,然后等待
  • 在没有收到服务器的消息之前,请继续显示加载符号,不要开始添加新单元格以准备任何操作,因为您可能无法获取更多数据,此时您必须删除页脚单元格,并让用户知道没有更多数据可检索,或者,如果要显示更多数据,则按以下顺序设置接下来的5个单元格:
    • 将新的5个数据对象添加到数据数组中
    • 使用
      numberofrowsinssection
      delegate方法更新节中的行数
    • 您将发现,一旦使用
      [myTable reloadTable]刷新表格,如果编码正确,单元格将正确显示

  • 我认为问题可能出在
    [self-downloadImage_3:indexath]
    当您在
    Button1
    调用
    dispatch\u async
    时,并且
    dispatch\u async
    块没有调用,然后单击
    Button2
    ,我猜
    msg\u array
    被清除并填充新的5对象,然后调用
    dispatch\u async
    块,块的
    path.row
    是28,而
    msg_数组
    有5个新对象的新数组内容,然后崩溃

    您应该在单击其他按钮之前取消
    dispatch\u async
    ,这对于
    dispatch\u async
    是不可能的,因此您可以在块中进行判断:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
        [self beginBackgroundFetchTask];
    
        [self downloadImage_3:indexPath buttonIndex:index];
    
        [self endBackgroundFetchTask];
    });
    
    -(void)downloadImage_3:(NSIndexPath *)path buttonIndex:(int)buttonIndex{
         if(self.currentSelectIndex != buttonIndex) return; //skip reloadData if not same index
    
    
            UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:ImagePath]]];
    
            if (img) {
                [dicImages_msg setObject:img forKey:[[msg_array objectAtIndex:path.row] valueForKey:@"Merchant_SmallImage"]];
            }
    
            [_tblList performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
    
    }
    

    尝试调试你的应用程序,在cellForRowAtIndexPath上设置断点。查看数组何时超出边界。您得到的错误是因为数组在特定的indexath.row上获取空值。原因:[[uuu nsarray-objectAtIndex:]:索引28超出边界[0..4],您试图访问索引28处的对象,但数组只有5个元素。您是对的,伙计,但是,当我单击按钮2时,我已经停止提取按钮1的数据,我正在初始化数组并再次提取按钮2的新数据,但是崩溃发生了,因为它仍然提取按钮1的数据,索引28是按钮1的,我应该如何停止按钮1的线程?单击
    按钮2
    为什么要将相同的响应复制并粘贴到每个答案上。这里的人都在帮你。对不起,伙计,我从过去4天就被困在这里,找不到答案:(你是对的,伙计,但是当我点击按钮2时,我已经停止提取按钮1的数据,我正在初始化我的数组并再次提取按钮2的新数据,但是崩溃发生了,因为它仍然提取按钮1的数据,索引28是按钮1的,我应该如何停止我的线程呢<代码>按钮1
    ?点击
    按钮2
    你是对的,伙计,但是当我点击
    按钮2
    时,我已经停止提取
    按钮1
    的数据,我正在初始化数组,并再次提取
    按钮2
    的新数据,但是崩溃发生了,因为它仍然提取
    按钮1
    的数据,索引28是无效的
    按钮1
    我应该如何停止我的
    按钮1
    线程?点击
    按钮2
    你是对的,伙计,但是当我点击
    按钮2
    时,我已经停止了提取
    按钮1
    的数据,我正在初始化我的数组并再次提取
    按钮2
    的新数据,但是崩溃发生了,因为它仍然存在获取
    按钮1的数据
    索引28是
    按钮1的
    如何停止
    按钮1的线程