0

2 つの異なるプロトタイプ セルから作成されたテーブルビュー セルに問題があります。独自のラベルと画像をそれらに追加します。

それらは正常に読み込まれますが、テーブルビューをスクロールしてセルを選択すると、他のセルのラベルがセルに既に存在するラベルに追加されます。

人々が抱えている同様の問題について読んだことがありますが、選択時にのみ発生するという事実に対処するものはありません。

追加してみましif (cell == nil){};たが、効果がありません。

私のcellForRowAtIndexPathは次のとおりです。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"NDSClassSubMenuViewController cellForRowAtIndexPath: running...");



    NDSClassAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    NSDictionary *childNodes = [appDelegate.children objectAtIndex:0];
    NSString *multicellstat = [childNodes objectForKey:@"@CELLTYPE"];
    NSLog(@"Multicellstat %@", multicellstat);
    NSLog(@"TESTING CHILD %@", childNodes);

    //ONLY LOADING SUB MENU OPTIONS
NSString *cellType;
    if (multicellstat == NULL){
        NSLog(@"cellForRowAtIndexPath: @CellType == multicell. Making multicell.");
        cellType = @"SegueCellSubmenu";
    }else {
        NSLog(@"cellForRowAtIndexPath: children variable is NOT NULL. Making MenuCell.");
        cellType = @"SegueCellMulti";

    }


    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellType forIndexPath:indexPath];

    if (multicellstat == NULL){
        NSLog(@"Not adding picture.");
    }else {


        dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //this will start the image loading in bg
        dispatch_async(concurrentQueue, ^{

            UIView *blackBG = [[UIView alloc] initWithFrame:CGRectMake(5, 5, 60, 60)];
            blackBG.backgroundColor = [UIColor grayColor];

            NSURL *imageURL = [NSURL URLWithString:[childNodes objectForKey:@"@THUMBNAIL"]];
        NSData *data = [NSData dataWithContentsOfURL:imageURL];
        UIImage *image = [UIImage imageWithData:data];

        UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
        imageView.frame = CGRectMake(0, 0, 60, 60);
            int borderWidth = 1;
            imageView.frame = CGRectMake(borderWidth, borderWidth, blackBG.frame.size.width-borderWidth*2, blackBG.frame.size.height-borderWidth*2);


            dispatch_async(dispatch_get_main_queue(), ^{

                [cell addSubview:blackBG];
                [blackBG addSubview:imageView];


         });
        });


    }


    //NSDictionary *tweet = [[[[appDelegate.menuItems objectForKey:@"Table"] objectForKey:@"Parent"]objectAtIndex:indexPath.row] objectForKey:@"Child"];
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(70, 10, 210, 30)];
    UILabel *detailText = [[UILabel alloc] initWithFrame:CGRectMake(70, 35, 210, 30)];

    [cell.contentView addSubview:label];
    [cell.contentView addSubview:detailText];


    NSString *text = [[appDelegate.children objectAtIndex:indexPath.row] objectForKey:@"@MENUDESC"];
    NSString *name = [[appDelegate.children objectAtIndex:indexPath.row] objectForKey:@"@MENUDESC"];
    //NSLog(@"cellForRowAtIndexPath MENU ITEMS %@", text);

    //Title label
    label.text = NULL;
    label.text = text;
    [label setFont: [UIFont fontWithName:@"Arial" size:16.0]];

//Detail label
    detailText.text = NULL;
    detailText.text = name;
    [detailText setFont: [UIFont fontWithName:@"Arial" size:12.0]];
    //detailText.textColor = [UIColor colorWithRed:186.0/255.0 green:186.0/255.0 blue:186.0/255.0 alpha:1];
    detailText.textColor = [UIColor grayColor];

    //cell.textLabel.text = text;
    //cell.detailTextLabel.text = [NSString stringWithFormat:@"by %@", name];


    NSLog(@"Creating submenu item: %@", text);
     NSLog(@"NDSClassSubMenuViewController: cellForRowAtIndexPath: finished.");



    return cell;

}

これを解決する方法を知っている人はいますか?

4

2 に答える 2

1

重要な問題は、synch を実行するコードが、イメージ リクエストの完了後に変更するセルが、イメージ リクエストの開始時と同じセル (同じ indexPath にある) であると想定してはならないことです。

正しいレシピは次のとおりです。

  1. キャッシュされた結果がある場合はそれを使用し (そのため、スクロールするたびに Web リクエストを実行しません)、それ以外の場合は非同期リクエストを作成します。
  2. リクエストが完了したら、結果をキャッシュします
  3. 元の indexPath を使用して、セルがまだ表示されているかどうかを判断します。存在する場合は、その indexPath をリロードします。新しくキャッシュされた結果は、cellForRowAtIndexPath で利用できるようになります。

以下は、非同期リクエストの後にテーブルで正しく更新する方法を説明するコードのスニペットです。cellForRowAtIndexPath で、これを呼び出す前にキャッシュされた応答を確認します。

// in cellForRowAtIndexPath:
NSString *urlString = [childNodes objectForKey:@"@THUMBNAIL"]
NSURL *imageURL = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:imageURL];
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
if (!cachedResponse) { 
    // we don't find this image/request in the cache, call asynch load
    [self asynchLoad:urlString forIndexPath:indexPath];
} else {
   // we got this image already, update the cell
    UIImage *image = [UIImage imageWithData:cachedResponse.data];
    // set the cell's UIImageView subview image to image
}

ここでは、urlString で画像を読み込み、結果をキャッシュし、リクエストの完了後もまだ表示されている場合は、読み込み後に indexPath を再読み込みします。

- (void)asynchLoad:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath {

    NSURL *imageURL = [NSURL URLWithString:[childNodes objectForKey:@"@THUMBNAIL"]];
    NSURLRequest *request = [NSURLRequest requestWithURL:imageURL];

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        if (!error) {

            // cache the response
            NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data];
            [[NSURLCache sharedURLCache] storeCachedResponse:cachedResponse forRequest:self];

            // important part - we make no assumption about the state of the table at this point
            // find out if our original index path is visible, then update it, taking 
            // advantage of the cached image (and a bonus option row animation)

            NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows];
            if ([visiblePaths containsObject:indexPath]) {
                NSArray *indexPaths = [NSArray arrayWithObject:indexPath];
                [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation: UITableViewRowAnimationFade];
                // because we cached the image, cellForRow... will see it and run fast
            }
        }
    }];
}
于 2013-03-10T16:51:32.593 に答える
0

独自のカスタム セル クラスを作成し、ストーリーボードを使用してレイアウトを設定することで、この問題を解決しました。

于 2013-03-12T13:07:13.817 に答える