0

我有一个段和一个表视图,我必须在表视图中重新加载数据,但当我快速切换段按钮时,应用程序崩溃。

在段上,我有三个按钮,在它们的操作上,我触发了对 url 的请求并从该 url 获取 json(分别为 3 个不同的 url,并在 json 中返回 10、17 和 8 个结果)。

我有一个自定义表格单元格,其中包含图像,我正在尝试延迟加载这些图像。

在 JSON 结果中,每个 json 对象都有不同的键,例如 name、id、imageurl 等。

id 在整个应用程序中是唯一的,我正在尝试加载图像并将图像保存在基于该唯一 id 的本地内存中,这样我就可以显示已兑现的图像,而无需在段更改时重新下载图像,因为有些条目在所有三个部分都是相同的。

这是我的完整代码

- (IBAction)segmentedControlIndexChanged {
NSString *offerRequestUrl = nil;
switch (self.mySegment.selectedSegmentIndex) {
    case 0:
        offerRequestUrl = @"url_one";
        self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
        break;
    case 1:
        offerRequestUrl = @"url_two";;
        self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
        break;
    case 2:
        offerRequestUrl = @"url_three";;
        self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
        break;

    default:
        break;
}
  [self parseJSONWithURL:self.feedRequestUrl];
}
- (void) parseJSONWithURL:(NSURL *) jsonURL
 {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData* data = [NSData dataWithContentsOfURL: jsonURL];
        [self performSelectorOnMainThread:@selector(fetchedData:) withObject:data waitUntilDone:YES];
    });
}

- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData
                                                     options:kNilOptions
                                                       error:&error];

self.feedsArray = [json objectForKey:@"result"];
[self.myTableView reloadData];
 }

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
 {
 int count = self.feedsArray.count;

// if there's no data yet, return enough rows to fill the screen
if (count == 0)
{
    return 1;
}
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {

// customize the appearance of table view cells
//
static NSString *CellIdentifier = @"MyTableCell";
static NSString *PlaceholderCellIdentifier = @"PlaceholderCell";

// add a placeholder cell while waiting on table data
int nodeCount = [self.feedsArray count];

if (nodeCount == 0 && indexPath.row == 0)
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];

    if (cell == nil)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                      reuseIdentifier:PlaceholderCellIdentifier];
        cell.detailTextLabel.textAlignment = UITextAlignmentCenter;
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

    cell.detailTextLabel.text = @"Loading . . .";

    [self performSelector:@selector(checkAndDisplayAlert) withObject:self afterDelay:10.0];

    return cell;
}

CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (nodeCount > 0)
{        
    // Configure the cell...
    cell.carImageView.image = [UIImage imageNamed:@"Placeholder"]; //acts as default image
    if([self.imageDict  valueForKey:[NSString stringWithFormat:@"%@", self.feedsArray[indexPath.row][@"id_str"]]]==nil)
    {
        [NSThread detachNewThreadSelector:@selector(displayingSmallImage:) toTarget:self withObject:indexPath];
    } else {
        cell.carImageView.image = [self.imageDict valueForKey:[NSString stringWithFormat:@"%@", self.feedsArray[indexPath.row][@"id_str"]]];
    }

    cell.imageView.clipsToBounds = YES;
    cell.titleLabel.text = self.feedsArray[indexPath.row][@"title_key"];

}
return cell;
 }

  - (void) displayingSmallImage:(NSIndexPath *)indexPath
{
NSString *imageUrl = self.feedsArray[indexPath.row][@"icon_url"];

NSURL *url = [NSURL URLWithString:imageUrl];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image == nil)
{
    image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Placeholder"]];
}
[self.imageDict setObject:image forKey:[NSString stringWithFormat:@"%@", self.feedsArray[indexPath.row][@"id_str"]]];
[self performSelectorOnMainThread:@selector(imageReceived:) withObject:indexPath waitUntilDone:NO];
  }

   - (void) imageReceived:(NSIndexPath *)indexPath
 {
UIImage *image = (UIImage *)[self.imageDict objectForKey: [NSString stringWithFormat:@"%@", self.feedsArray[indexPath.row][@"id_str"]]];
UIImageView *imgs = (UIImageView *)[[self.myTableView cellForRowAtIndexPath:indexPath] viewWithTag:IMG_TAG];
[imgs setImage:image];
[self.myTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
  }

  - (void) checkAndDisplayAlert
{
if (!self.feedsArray && self.isAlertPresent == NO) {
    UIAlertView *nilAlert = [[UIAlertView alloc] initWithTitle:@"Sorry!"
                                                       message:@"No result returned from server."
                                                      delegate:self
                                             cancelButtonTitle:@"OK"
                                             otherButtonTitles:nil];
    [nilAlert setTag:kNilAlertTag];
    self.isAlertPresent = YES;
    [nilAlert show];
}
 }

我要做的主要事情是

  1. 懒惰下载图片

  2. 根据唯一 ID 将图像缓存在本地内存中

  3. 检查已下载图像的兑现图像字典并显示它

  4. 如果可能的话,将这些下载的图像保存在本地内存中(nsuserdefaults 等),这样如果用户重新启动应用程序,图像也会在那里并且可以根据其唯一 ID 显示,无需再次下载。

任何帮助,将不胜感激。

4

2 回答 2

0

请发布错误日志,如果是数组越界异常我怀疑这两种方法

- (void)fetchedData:(NSData *)responseData & your tableViewDatasource

要查找导致此崩溃的代码行,请执行此操作。转到左侧的断点选项卡,然后单击底部的 +。

在此处输入图像描述

然后你会得到这样的东西:

在此处输入图像描述

刚刚完成,再次运行您的代码并告诉我们哪一行导致了异常。

我理解你的问题,为什么要在这个函数中从数组中获取 URL

  - (void) displayingSmallImage:(NSIndexPath *)indexPath

您可以从 cellForRowAtIndex 传递 Url 以加载到该函数,如下所示:

    NSArray *argsToPass=[NSArray arrayWithObjects:indexPath,self.feedsArray[indexPath.row][@"icon_url"]];

    [NSThread detachNewThreadSelector:@selector(displayingSmallImage:) toTarget:self withObject:argsToPass];

并且您的功能被修改为:

 - (void) displayingSmallImage:(NSArray *)args
{

  if([args count] == 0)
 {
NSString *imageUrl = [args objectAtIndex:1];

NSIndexPath *indexPath=[args objectAtIndex:0]; 

NSURL *url = [NSURL URLWithString:imageUrl];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image == nil)
{
    image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Placeholder"]];
}
[self.imageDict setObject:image forKey:[NSString stringWithFormat:@"%@", self.feedsArray[indexPath.row][@"id_str"]]];
[self performSelectorOnMainThread:@selector(imageReceived:) withObject:indexPath waitUntilDone:NO];
  }
 }
于 2013-06-20T04:42:56.147 回答
0

当您向服务器发送请求时,您可以设置 self.view.userInteractionEnabled=NO。当你获得数据时,只需启用用户交互。这样就可以避免多个请求。

于 2013-06-21T13:12:47.900 回答