0

私は iphone 開発にまったく慣れていないので、アプリケーションで奇妙なクラッシュが発生しています。実際、メモリ警告をシミュレートした後、私のアプリケーションは常にクラッシュします。私は毎回この動作を再現することができ、障害のある行を分離することができました:)。

カスタムUITableViewCellsを提供するカスタムUITableViewControllerで作業しています。

@implementation CustomTableViewController
// [...]
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{   
static NSString *CellIdentifier = @"MyTableViewCell";
UITableViewCell *cell = nil;

if ([indexPath row] < [dataList childCount])
{
    cell = [tv dequeueReusableCellWithIdentifier:CellIdentifier];

    if (nil == cell) 
    {
        cell = [[[KpowUITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
                                          reuseIdentifier:CellIdentifier] autorelease];

        KUICustomView* customView = [[KUICustomView alloc]initWithFrame:CGRectZero];
        [(KpowUITableViewCell*)cell setFrontView:customView];
        [customView release];
    }

    KUICustomView* cView = [(KpowUITableViewCell*)cell frontView];
    [cView setDataObject:[dataList getChildAtIndex:[indexPath row]]]; // The crash happens in this function
}
// [...]

セルビューのカスタムデータオブジェクトを設定する関数は次のとおりです。

-(void)setDataObject:(DataObject *)do
{
    [do retain];
    [dataObject release];
    dataObject = do;

    NSString* defaultPath = [NSString stringWithFormat:@"%@/default_image.png", [[NSBundle mainBundle] resourcePath]];
    UIImage* defaultImage = [[UIImage alloc] initWithContentsOfFile:defaultPath];
    [self setImage: defaultImage];//[UIImage imageNamed:@"default_image"]]; // The crash happens in this function
    [defaultImage release];
    // [...]

そして最後に、ここで魔法が起こります:

-(void)setImage:(UIImage *)img
{
    [img retain];
    NSLog(@"setImage : old image > %@/%@/%i", [image description],         [[image class]description], [image retainCount]);
    [image release]; // CRASH EXC_BAD_ACCESS
    image = img;

    [self setNeedsDisplay];
}

したがって、通常のシナリオではすべてが正常に機能します。しかし、メモリ警告をシミュレートし、UITableView をスクロールすると、これらすべての関数が呼び出され、アプリケーションがクラッシュします。[image release] を削除すると、クラッシュは発生しません (ただし、「はい、メモリ リークが発生します」)。NSLog の出力は常に次のようになります。

setImage : old image > <UIImage: 0x4b54910>/UIImage/1

何が間違っているのか、この問題を回避するために何ができるのか、本当にわかりません。Xcodeデバッガーのスクリーンショットは次のとおりです...

http://img30.imageshack.us/i/debuggerscreen.png/

どんな助けでも大歓迎です。前もって感謝します

編集 1: @bbum Build and Analyze は、無関係な警告をいくつか表示しましたが、それでも有用です。それがそこにあるのさえ見ませんでした

画像を設定した場所がもう 1 つあります。ではsetDataObject、イメージは単なるプレースホルダです。実画像のダウンロードを非同期で起動し、 に戻しrequestDidFinishLoadます。メソッドは次のようになります。

- (void)requestDidFinishLoad:(KURLRequest*)request
{
    if (request == currentRequest) 
    {
        UIImage* img = [[UIImage alloc] initWithData:[request data]];

        if (nil != img)
            [self setImage:img];

        [img release];
    }

    if (currentRequest == request)
        currentRequest = nil;
    [request release];
}

NSZombie Detection で計測器を実行しましたが、結果は別の方向を示しているようです。スクリーンショットは次のとおりです。

http://img13.imageshack.us/i/zombieinstrument.jpg/

それをどうするかはまだよくわかりませんが、調査は進んでいます:)

4

5 に答える 5

4
[image release]; // CRASH EXC_BAD_ACCESS

バックトレースは、 のdeallocメソッドでクラッシュしていることを示していますUIImage。あなたはimageどこかで過剰に解放されました。

まず、「ビルドと分析」を試して、有用な警告が表示されるかどうかを確認します。それらを修正します。

次に、ゾンビ検出をオンにして、問題の再現を試みます。それは手がかりを提供するかもしれません。

@propertyセッター/ゲッターメソッドのペア(またはそれらの1つ)を宣言するための「単なる」利便性で あることに注意してください。メソッドを直接[foo setImage:bar]使用または宣言するかどうかに関係なく、まったく同じです。@property同様にfoo.image = bar;とまったく同じ[foo setImage:bar];です。

最後に、それはあなたのを処理するすべてのコードimageですか? メモリ不足の警告をどのように処理しますか?

また、セッターがを呼び出さなかっsetNeedsDisplay:た方がよいでしょう。単純なセッター/ゲッターを使用し@propertyます@synthesize。次に、セッターを呼び出すときは、setNeedsDisplay:後で回線を呼び出します。これにより、UI を設定する業務と、いつ表示する必要があるかを判断する業務を切り離すことができます。


あはは!あなたのゾンビはとても役に立ちました。特に、URLConnection を時期尚早に解放しているように見えます。これにより、NSData があまりにも早く解放されます。これが問題の原因である可能性が高く、少なくとも、この問題を修正する前に修正する必要があります。

于 2011-02-16T16:43:27.653 に答える
0

nil に設定せずに、メモリ警告に応答してイメージを解放している可能性があります。したがって、呼び出しsetImage:ているときは、すでに解放されているオブジェクトを解放しているため、クラッシュします。次のようなものを試してください:

- (void)viewDidUnload {
    [super viewDidUnload];
    [image release]; image = nil;
}

またはimageプロパティとして宣言されている場合

- (void)viewDidUnload {
    [super viewDidUnload];
    self.image = nil;
}
于 2011-02-16T08:23:55.800 に答える
0

特に @sabby の誤解に対処するには:

-(void)setImage:(UIImage *)img
{
    [img retain]; // img rc +1
    image = img; 
    if(image)
    {
        [image release]; // img rc -1
    }
    // image set, but not retained by `self`
}

最終結果?アイテム セットを保持しないセッター メソッド。それを次と組み合わせる:

- initWithImage:anImage
{
     if (self=[super init]) {
           image = [anImage retain];
     }
     return self;
}

上記のセッターは、 に渡された元のイメージをリークinitし、 に渡されたイメージを過剰に解放しsetImage:、アプリが十分長く存続する場合、次のようにクラッシュする可能性が非常に高くなります。

- (void) dealloc
{
    [image release];
    [super dealloc];
}
于 2011-02-17T17:53:04.363 に答える
-1

こうすれば助かります

-(void)setImage:(UIImage *)img
{
    [img retain];
    NSLog(@"setImage : old image > %@/%@/%i", [image description],         [[image class]description], [image retainCount]);
     // CRASH EXC_BAD_ACCESS
    image = img;
if(image)
{
[image release];
}

    [self setNeedsDisplay];
}

自分で確認したことはありませんが、クラッシュの理由はイメージのリリースです。

于 2011-02-16T05:46:42.497 に答える