0

In my application, i have a tableview. And each cell contains, a UIButton, UIImageView and a UILabel. And when click on the button, a group of files will be downloaded using ASINetworkQueue, at this time the button will be replaced with UIProgressView. While the download progress, if I scroll the table, the app crashes. And I am getting the error point in ASIHTTPRequest.m class,

+ (void)updateProgressIndicator:(id *)indicator withProgress:(unsigned long long)progress ofTotal:(unsigned long long)total
{
    #if TARGET_OS_IPHONE
        // Cocoa Touch: UIProgressView
        SEL selector = @selector(setProgress:);
        float progressAmount = (float)((progress*1.0)/(total*1.0));

    #else
        // Cocoa: NSProgressIndicator
        double progressAmount = progressAmount = (progress*1.0)/(total*1.0);
        SEL selector = @selector(setDoubleValue:);
    #endif

    if (![*indicator respondsToSelector:selector]) { // here i am getting the error 
        return;
    }

    [progressLock lock];
    [ASIHTTPRequest performSelector:selector onTarget:indicator withObject:nil amount:&progressAmount callerToRetain:nil];
    [progressLock unlock];
}

And here is my code: I have written a UITableViewCell class like,

@interface UIMenuItemCell : UITableViewCell{
    UILabel *cellItemName;
    UIImageView *cellitemImage;
    UIButton *cellItemButton;
    UIProgressView *cellItemProgress;
}
@property (nonatomic, retain) UILabel *cellItemName;
@property (nonatomic, retain) UIImageView *cellitemImage;
@property (nonatomic, retain) UIButton *cellItemButton;
@property (nonatomic, retain) UIProgressView *cellItemProgress;

and

- (UIMenuItemCell *) getCellContentView:(NSString *)cellIdentifier {

    CGRect CellFrame = CGRectMake(0, 0, 150, 60);
    CGRect imgFrame = CGRectMake(20, 48, 110, 123);
    CGRect btnFrame = CGRectMake(25, 140, 100, 26);

    UIImageView *itemImg;
    UIButton *itemBtn;

    UIMenuItemCell *cell = [[UIMenuItemCell alloc] init] ;
    cell.frame = CellFrame;

    //Initialize ImageView
    itemImg = [[UIImageView alloc]initWithFrame:imgFrame];
    itemImg.tag = 2;
    [cell.contentView addSubview:itemImg];

    //Initialize Button
    itemBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    itemBtn.frame = btnFrame;
    itemBtn.tag = 3;
    itemBtn.titleLabel.textColor = [UIColor blueColor];
    itemBtn.titleLabel.font = [UIFont systemFontOfSize:9.0];
    [cell.contentView addSubview:itemBtn];

    return cell;
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UIMenuItemCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if(cell == nil)
        cell = [self getCellContentView:CellIdentifier];

    cell.cellitemImage = (UIImageView *)[cell viewWithTag:2];
    cell.cellItemButton = (UIButton *)[cell viewWithTag:3];

    DataBaseClass *itemObj = [appDelegate.itemArray objectAtIndex:indexPath.row];
    NSString *url;
    if ([itemObj.itemStatus isEqualToString:@"NotAvailable"]) {
        url = [NSString stringWithFormat:@"%@",itemObj.notAvialableIcon];
        [cell.cellItemButton setTitle:date forState:UIControlStateNormal]; 
        cell.cellItemButton.userInteractionEnabled = NO;
        cell.userInteractionEnabled = NO;
        [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"not_available_bttn_bck_img"] forState:UIControlStateNormal];
    }else if([itemObj.itemStatus isEqualToString:@"Available"]){
        cell.cellItemButton.userInteractionEnabled = YES;
        cell.userInteractionEnabled = YES;
        [cell.cellItemButton setTitle:@"" forState:UIControlStateNormal];
        [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"img_normal"] forState:UIControlStateNormal];
        [cell.cellItemButton setBackgroundImage:[UIImage imageNamed:@"img_pressed"] forState:UIControlStateHighlighted];
        [cell.cellItemButton addTarget:self action:@selector(download) forControlEvents:UIControlEventTouchUpInside];
        url = [NSString stringWithFormat:@"%@",itemObj.availableIcon];
    }

    [cell.cellitemImage setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:@"item01.png"]];

    cell.cellItemName.text = [NSString stringWithFormat:@"%@",itemObj.itemName];

    return cell;
}

and the download action:

- (void)download{
//adding custom method to add the uiprogressview into the selected cell
//and setting the progress delegate for the queue
[self.myQueue setDownloadProgressDelegate:currentProgress];
//then starts download
[self.myQueue go];
}

Please share your thoughts. Edit: Here I am implementing multiple downloads at the same time.

Kara
  • 6,115
  • 16
  • 50
  • 57
Mithuzz
  • 1,091
  • 14
  • 43

2 Answers2

1

What is happening is that when your cell goes out of screen the progress bar gets released and ASI will try to update a released object, what you have to do is to separate the two from each other, you could create a downloader class and let this class send notifications to cell, please note that this will require some work at your side, good luck :)

Omar Abdelhafith
  • 21,163
  • 5
  • 52
  • 56
  • good suggestion, but as you said it will need some more work. So can you give any tutorial or sample code to implement this? – Mithuzz Jun 17 '12 at 20:47
1

@Omar is correct about the problem. Here's a sketch of a solution:

Add a property like "downloadProgress" to DatabaseClass. This can be a float who's value is negative when no download is happening and between 0.0 and 1.0 while download is occurring.

Add a hidden progress indicator to your custom cell.

When download button is pressed, get the corresponding database item and start the download (setting the item's downloadStatus to 0.0). As you get progress from the asynch process, update that item's downloadStatus.

Each time you do that, let the table know that status is changed (NSNotification might be a good mechanism here). The table VC should call reloadRowsAtIndexPaths: with an array containing the index path corresponding to the database item.

When configuring the cell, the table VC should check the item's download status. If it's positive, unhide the status indicator and set it's progress according to the float.

Also, about the crash: it looks like there's at least one other problem in the updateProgress method where the indicator is typed (id *). This is like a pointer to an id, and almost certainly not what you want. Just use id, and don't refer to indicator in the body as *indicator.

danh
  • 62,181
  • 10
  • 95
  • 136