1

こんにちは私はNSOperationQueueを使用してバックグラウンドで画像をダウンロードしています。画像をダウンロードするためのカスタムNSOperationを作成しました。画像をテーブルセルに入れます。問題は、[operationQueue setMaxConcurrentOperationCount:10]を実行し、いくつかのセルを下にスクロールすると、プログラムがEXC_BAD_ACCESSでクラッシュすることです。テーブルの同じ場所でクラッシュするたびに。同じ会社のもので同じロゴのセルが3つ並んでいるので、基本的には3回画像をダウンロードする必要があります。それ以外の場合は正常に動作します。


- (void) main
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSURL *url = [[NSURL alloc] initWithString:self.imageURL];
    debugLog(@"downloading image: %@", self.imageURL);
    //NSError *error = nil;
    NSData *data = [[NSData alloc] initWithContentsOfURL:url];
    [url release];

    UIImage *image = [[UIImage alloc] initWithData:data];
    [data release];
    if (image)
    {
        if (image.size.width != ICONWIDTH && image.size.height != ICONHEIGHT)
        {
            UIImage *resizedImage;
            CGSize itemSize = CGSizeMake(ICONWIDTH, ICONHEIGHT);

                        //!!! UIGraphicsBeginImageContext NOT THREAD SAFE
            UIGraphicsBeginImageContext(itemSize);
            CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
            [image drawInRect:imageRect];
            resizedImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();

            self.theImage = resizedImage;
        }
        else
        {
            self.theImage = image;
        }
        [image release];
    }
    [delegate didFinishDownloadingImage: self];
    [pool release];
}

これは私が画像のダウンロードを処理する方法です。上記の関数でコメントアウトし [delegate didFinishDownloadingImage: self]; てもクラッシュしませんが、もちろん役に立ちません。


-(void) didFinishDownloadingImage:(ImageDownloadOperation *) imageDownloader
{
    [self performSelectorOnMainThread: @selector(handleDidFinishDownloadingImage:) withObject: imageDownloader waitUntilDone: FALSE];
}

-(void) handleDidFinishDownloadingImage:(ImageDownloadOperation *)imageDownloadOperation
{
    NSArray *visiblePaths = [self.myTableView indexPathsForVisibleRows];
    CompanyImgDownloaderState *stateObject = (CompanyImgDownloaderState *)[imageDownloadOperation stateObject];

    if ([visiblePaths containsObject: stateObject.indexPath])
    {
        //debugLog(@"didFinishDownloadingImage %@ %@", imageDownloader.theImage);

        UITableViewCell *cell = [self.myTableView cellForRowAtIndexPath: stateObject.indexPath];
        UIImageView *imageView = (UIImageView *)[cell viewWithTag: 1];
        if (imageDownloadOperation.theImage)
        {
            imageView.image = imageDownloadOperation.theImage;
            stateObject.company.icon = imageDownloadOperation.theImage;
        }
        else
        {
            imageView.image = [(TestWebServiceAppDelegate *)[[UIApplication sharedApplication] delegate] getCylexIcon];
            stateObject.company.icon = [(TestWebServiceAppDelegate *)[[UIApplication sharedApplication] delegate] getCylexIcon];
        }

    }
}


4

3 に答える 3

4

このメーリングリストの投稿によると、UIGraphicsBeginImageContextスレッドセーフではありません。CGBitmapContextCreate投稿は、および関連する関数がそれを行うための安全な方法であることを示唆しています。

http://osdir.com/ml/cocoa-dev/2009-10/msg00035.html

于 2010-03-30T13:17:55.070 に答える
1

テーブルビューにないセルにアクセスしようとしているため、クラッシュしていると思います。

論理テーブルの長さに関係なく、ビジュアルテーブルビューには、現在画面に表示されている論理テーブルのセクションを表示するのに十分なセルしか保持されません。デフォルトの行サイズでは、テーブルには9〜10個のセルオブジェクトのみが表示されます。たとえば、100行の長さの論理テーブルがあり、ビューに行11〜20が表示されている場合、テーブルには9つのセルオブジェクトしかありません。行89〜98を表示すると、まったく同じ9つのセルオブジェクトしかありません。どの行を表示しても、同じ9つのセルオブジェクトが何度も表示されます。変更されるのは、表示されるデータだけです。

画面外の論理行のセルにアクセスしようとしても、何も返されません。あなたの場合、11番目の論理行にアクセスしようとしますが、11番目のセルはなく、決してありません。

セルの内容を設定してテーブルビュー自体にデータを格納しようとしているため、概念的に混乱していると思います。テーブルビューにはすぐに表示されるデータ以外のデータは保存されないため、これは機能しません。スクロールするときにテーブルビューがより多くの行を表示する必要がある場合、テーブルビューは既存のセルを再利用し、そのDataSourceデリゲートは既存のセルが表示するデータを変更します。

画像をセルに保存する代わりに、データモデルを作成し、そこに画像を保存する必要があります。次に、テーブルビューがスクロールするtableview:cellForRowAtIndexPath:と、データソースデリゲートに送信されます。次に、データソースデリゲートは、データモデルに論理行のデータを要求し、再利用されたセルにデータを入力して、テーブルビューに返します。

于 2010-03-30T14:46:48.873 に答える
0

codewarriorのおかげで解決したようです。変更した部分です。

@同期 (デリゲート)
{
    UIImage *resizedImage;
    UIGraphicsBeginImageContext(itemSize);
    CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
    [image drawInRect:imageRect];
    resizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    self.theImage = resizedImage;
}
于 2010-03-31T06:56:05.687 に答える