10

アプリケーションと iOS5 b7 および GM バージョンとの互換性に問題があります。

この問題は、次のコード行で発生します。

do {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!done);

EXC_BAD_ACCESSいくつかの反復の後、シグナルでアプリがクラッシュします。

渡された反復回数はランダムです (2 から 7 まで)。

また、すべてが iOS4 および iOS3 で非常にうまく機能します。

同じ問題が Apple のサンプル: XMLPerformance Sampleで発生します。

これについてあなたはどう思いますか?

10 月 12 日に何千人ものユーザーが私のアプリを iOS5 にアップグレードしますが、AppStore でこのような奇妙なエラーがアプリに表示されるのは望ましくありません。

4

4 に答える 4

10

4 時間が経過し、問題が見つかりました。で問題をどのように解決したかを説明しますXMLPerformance sample

問題はにありましたNSAutoreleasePool。あります@property (nonatomic, assign) NSAutoreleasePool *downloadAndParsePool;。アプリがダウンロードを開始すると、Top300 Paid Apps RSSを使用して新しいスレッドが作成され[NSThread detachNewThreadSelector:@selector(downloadAndParse:) toTarget:self withObject:url];ます。したがって、そのスレッドでは、ローカルの自動解放プールを保持する必要があります。それは次の方法で行われます。

- (void)downloadAndParse:(NSURL *)url {
    self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];

    // initializing internet connection and libxml parser.
    if (rssConnection != nil) {
         do {
             [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
         } while (!done);
    }
    // Release resources used only in this thread.
    [downloadAndParsePool release]; 
    self.downloadAndParsePool = nil;
}

だから、downloadAndParse:すべてがうまく見えます。次に、RSS からの項目が解析されるときに呼び出される 1 つのメソッドを見てみましょう。

- (void)finishedCurrentSong {
    // sending new item to delegate and other ...
    countOfParsedSongs++;
    // Periodically purge the autorelease pool. The frequency of this action may need to be tuned according to the 
    // size of the objects being parsed. The goal is to keep the autorelease pool from growing too large, but 
    // taking this action too frequently would be wasteful and reduce performance.
    if (countOfParsedSongs == kAutoreleasePoolPurgeFrequency) {
        [downloadAndParsePool release];
        self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];
        countOfParsedSongs = 0;
    }
}

ご覧のとおり、次の行があります。

[downloadAndParsePool release];
self.downloadAndParsePool = [[NSAutoreleasePool alloc] init];

したがって、まさにその行が例外を引き起こします。それらにコメントすると、すべてうまくいきます。

しかし、その行をコメントするだけでなく、より効率的であると言われているブロックに置き換えることNSAutoreleasePool- (void)downloadAndParse:(NSURL *)urlしました。@autorelease

- (void)downloadAndParse:(NSURL *)url {
@autoreleasepool {

    // initializing internet connection and libxml parser.
    if (rssConnection != nil) {
         do {
             [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
         } while (!done);
    }
    // Release resources used only in this thread.
    }
}

今、すべてが正常に動作します。私が解決していない唯一の問題は次のとおりです。

// Periodically purge the autorelease pool. The frequency of this action may need to be tuned according to the 
// size of the objects being parsed. The goal is to keep the autorelease pool from growing too large, but 
// taking this action too frequently would be wasteful and reduce performance.

したがって、誰かがこの問題について考えている場合は、別の回答を投稿して、バグ修正をより正確に説明してみてください。その答えを喜んで受け入れます。

ありがとう。

于 2011-10-06T14:21:06.170 に答える
2

これはメモリの問題のようです。Apple Technote QA1367「Cocoa プロジェクトで EXC_BAD_ACCESS バグを見つける」を確認してください。

あなたのコードで、これを試してできるだけ早くクラッシュさせてください:

[item release], item = nil;

これは問題を解決するものではありません。単にクラッシュを早期に発生させ、より意味のあるコールスタックを調査できるようにするだけです。

マルチスレッドを使用している場合は、まあ...「現在の」スレッドIDをコンソールに出力して、すべてが実行されていると予想されるスレッドで実際に実行されていることを確認できます。特に、そのようなコードが他のコードの副作用 (エラー ポップアップなど) として実行される場合でも、すべての UI がメイン スレッドにあることを確認してください。

#include <pthread.h>
- (void)myFunction
{
    NSLog(@"Thread (%d)",
        pthread_mach_thread_np(pthread_self()));
}

アプリをInstrumentsで実行し、メモリ検証が 1 ~ 2 秒ごとに実行されるように変更してください。遅いですが、実際のメモリの問題にできるだけ近い通知を受け取りたいと考えています。

于 2011-10-06T09:39:32.373 に答える
1

あなたのコードを見てください: その「完了」変数はどこから来て、誰がいつその値を変更したのですか? 今ではかなり魔法のように見えます。

また、runMode:beforeDate の戻り値をチェックして、実行されたことを確認することもできます。戻り値が NO の場合、runLoop はまったく実行されていません。コードの他の部分がそのようなケースを処理できないのではないでしょうか?

于 2011-10-06T10:15:09.203 に答える
0

ほんの少しの貢献です。

私は同じ問題を抱えているので、iOS5 では、スレッドに独自の NSAutoreleasePool を持つ必要がないことを発見しました (performSelectorOnMainThread によって使用されます)。

次に、コード (xml パーサー - 私と同じ) で、コードを iOS4 と iOS5 から分離する必要があると思います。

iOS4 では NSAutoreleasePool が必要ですが、iOS5 では必要ありません。

于 2011-10-12T16:39:44.303 に答える