0

最初のビューにボタンがある小さなiPhoneアプリがあります。このボタンを選択すると、画像が表示されている新しいビューが読み込まれます。私は現在、次のコードを使用して、ユーザーがアプリケーションの制御を継続できるようにしながら、別のスレッドでオンラインソースから画像をロードしています。

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

    NSURL *url = [[NSURL alloc] init];
    url = [NSURL URLWithString:logoPath];

    NSData *data = [[NSData alloc] init];
    data = [NSData dataWithContentsOfURL:url];

    loadingImage = [UIImage imageWithData:data];
    titleLogoImage.image = loadingImage;

    //[pool drain];
    [pool release];
}

これは、新しいビューのinitの次のコード行から呼び出されます。

[NSThread detachNewThreadSelector:@selector(loadImageTest) toTarget:self withObject:nil];

これで問題なく動作しますが、新しいビューを閉じてから、新しいビューをすばやく連続して(または場合によってはその直後に)再度ロードすると、従来のEXC_BAD_ACCESSで爆破されます。これはスレッドプール内のコードが原因であると確信していますが、なぜこれが発生しているのか誰かがわかりますか?

ありがとう

4

3 に答える 3

2

あなたの:

//これは問題ありません。独自のスレッドを作成する代わりに、//NSURLConnections非同期メソッドを使用してみてください。[NSThread detachNewThreadSelector:@selector(loadImageTest)toTarget:self withObject:nil];

- (void)loadImageTest
{
    // This is fine
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    // you're making and then abandoning this url object so it will leak
    NSURL *url = [[NSURL alloc] init];
    // this is fine
    url = [NSURL URLWithString:logoPath];
    // again making and abandoning an object
    NSData *data = [[NSData alloc] init];
    data = [NSData dataWithContentsOfURL:url];
    // this works, but is not thread safe,
    // can't operate on UIKit objects off the
    // main thread
    loadingImage = [UIImage imageWithData:data];
    titleLogoImage.image = loadingImage;
    // this is fine
    //[pool drain];
    [pool release];
}

スレッドセーフなどのためにクリーンアップされました。役立つはずです:

// I'm assuming you have a iVar for logoPath but we don't want to
// make threaded calls to an iVar (it's not mutable, so you could do it, but it's just bad form)
// If i'm wrong about logoPath being an iVar don't sweat copying it.
- (void)whateverMethodYouWant
{
    NSString *aLogoPath = [[logoPath copy] autorelease];
    [NSThread detachNewThreadSelector:@selector(loadImageForPath:) toTarget:self withObject:aLogoPath];
}
- (void)loadImageForPath:(NSString *)aLogoPath
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:aLogoPath]];
    // the performSelector will retain the data until the method can be performed
    [self performSelectorOnMainThread:@selector(setImageForTitleLogo:) withObject:imgData waitUntilDone:NO];

    [pool release];
}
- (void)setImageForTitleLogo:(NSData *)imgData
{
    // This part is not strictly necessary
    // but it's a nice way to wrap a method that needs to happen on the main thread.
    if ([NSThread isMainThread])
    {
        // make the image (i'm assuming you meant loadingImage to be a local scope variable)
        UIImage *loadingImage = [UIImage imageWithData:imgData];
        // make sure the button still exists 
        // also make sure you're setting any references to this button to nil when you're releasing and making new views
        // so that you're not addressing a button that's been released
        // (assigning the image to the button will cause the button to retain it for you)
        if (titleLogoImage != nil)
            titleLogoImage.image = loadingImage;
    }
    else
    {
        [self performSelectorOnMainThread:@selector(setImageForTitleLogo:) withObject:imgData waitUntilDone:NO];
    }
}
于 2010-07-29T03:41:29.627 に答える
0

あなたは奇妙なことをしている。

NSURL *url = [[NSURL alloc] init];

NSURL自分が所有するオブジェクトを作成することを意味します。

url = [NSURL URLWithString:logoPath];

これは、自動解放される別のNSURLオブジェクトを作成することを意味します。作成したNSURLは、リークするだけです。ここのNSDataについても同じことが言えます。

loadingImageによって保持する必要があります。そうしないtitleLogoImageと、のドレインに割り当てが解除されますNSAutoReleasePool。それは何でありtitleLogoImage、それは保持しimageますか?

psを編集するloadingImage:私を悩ませているのは、それが関数の範囲に限定されていないということです。物事を短くするには:

NSURL *url = [NSURL URLWithString:logoPath];
NSData *data = [NSData dataWithContentsOfURL:url];
titleLogoImage.image = [UIImage imageWithData:data];

少なくともいくつかの頭痛を救うかもしれません。

于 2010-07-28T23:30:04.117 に答える
0

投稿されたコードには、クラッシュを引き起こすものは何もありません。titleLogoImageの定義方法によっては、自動リリースの影響を受ける可能性があります。

ただし、mvdsで概説されている問題以外に、ローカライズされた自動解放プールの差し迫った必要はありません。ここでは何もしませんが、問題が発生します。

自動解放プールは危険であり、初心者には適していません。それらは、それらの中にある自動解放されたオブジェクトをすべて強制終了します。通常、メモリを大量に消費するオブジェクトを大量に作成する場合にのみ、独自のプールを作成します。ここではそうではないようです。

それらに注意が払われているにもかかわらず、カスタムプールはめったに使用されません。10年以上のAppleAPIの作業の後、私はおそらく自分のカスタムプールを使用した回数を数えることができます。

于 2010-07-29T00:01:16.837 に答える