3

私は途方に暮れています!特定の条件下でのみ発生する厄介なバグの 1 つですが、条件と結果を直接関連付けることはできません。

私のアプリにはページ化された UIScrollView があり、各ページのビューは UITableViewController のサブクラスである MyViewController から取得されます。メモリ使用量を最小限に抑えるために、現在表示されていないコントローラーをアンロードします。これが私の「クリーニング」方法です。

- (void) cleanViewControllers:(BOOL)all {

    if (all) { 
    // called if some major changes occurred and ALL controllers need to be cleared

        for (NSInteger i = 0; i < [viewControllers count]; i++)
            [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
    }
    else if ([viewControllers count] > 2) {
    // called if only the nearest, no longer visible controller need to be cleared
        NSInteger i = pageControl.currentPage - 2;
        if (i > -1) [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
        i = pageControl.currentPage + 2;
        if (i < [viewControllers count]) [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
    }
}

アプリをクラッシュさせるのは次の行です。

viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];

viewControllers は、MyViewController タイプのオブジェクトを含む NSMutableArray です。MyViewController にはカスタム プロパティがなく、その dealloc メソッドには [super dealloc] 呼び出ししか含まれていません。

デバッガーが表示するものは次のとおりです。 代替テキスト http://a.imageshack.us/img831/3610/screenshot20100806at126.png

問題は、コントローラーがクリアされるたびにこれが発生するわけではなく、時々発生することです。具体的には、特定の変更により ScrollView の完全なクリーニングと再描画がトリガーされた後、現在のページ (X と呼びます) が正常に表示されますが、X をクリーニングするのに十分な距離までスクロールするとすぐに、このクラッシュが発生します。それは私を夢中にさせています!

また、これは 4.0 シミュレーターや iPad では発生しませんが、3.1.3 を実行している第 1 世代の iPod touch では一貫して発生します。

4

4 に答える 4

6

何かが解放されていますが、ポインターはまだぶら下がっています。NSZombieEnabled を YES に設定し、再度実行します。方法は次のとおりです。

  • 製品 -> スキームの編集
  • 「引数」タブを選択します
  • 「環境に設定する変数」に追記
    • 名前: NSZombieEnabled
    • 値: はい

Xcode 4.1 以降の場合:

  • 製品 -> スキームの編集
  • 「診断」タブを選択します
    • ゾンビ オブジェクトを有効にするオプションがあります。

アプリを再度実行します。ある時点で、既に解放されたオブジェクトにアクセスしていることがわかります。そこから、誰がオブジェクトを保持していないか、または誰が過度に解放しているかを把握する必要があります。

ハッピーゾンビハンティング。

于 2010-08-06T18:45:52.340 に答える
1

多くの場合、これは、ViewController 内で何かを割り当て、それを何かに設定してから解放することによって発生する可能性があります。次に例を示します。

UIBarButtonItem* timeLabel = [[UIBarButtonItem alloc] initWithTitle:@"time" style:UIBarButtonItemStylePlain target:nil action:nil];

NSArray *items = [NSArray arrayWithObjects: timeLabel, nil];

self.toolbarItems = items;

この後に行うべき自然なことは次のとおりです。

[timeLabel release];

しかし、これにより [super dealloc] で EXC_BAD_ACCESS が発生します。おそらく、ビュー コントローラーが配列とその中のすべてのアイテムを解放するためです。

于 2011-05-26T15:07:38.527 に答える
0

ビュー コントローラーは、デフォルトでメモリ警告が発生すると自動的にビューをアンロードするため、大きなオーバーヘッドがない限り、コントローラー自体をアンロードする理由はありません。

ビューコントローラーのビューはまだビュー階層にありますか? などで確認できます[viewController isViewLoaded] && viewController.view.superview。その場合、View Controller を削除するのはおそらく安全ではありません。

( UIViewController.view がまだロードされていない場合はビューをロードするため、 isViewLoaded チェックに注意してください。)

于 2010-08-06T19:11:31.393 に答える
-1

配列内の要素を置き換える代わりに、単純に呼び出すremoveObjectAtIndex:removeAllObjects:、参照を保持すべきではない場所に何も保持していないことを確認できます。

于 2010-08-06T18:57:04.307 に答える