0

次のエラーが表示されます。

スタックトレースなし。

-[__NSArrayI countByEnumeratingWithState:objects:count:]: message sent to deallocated instance

このメソッドを何と呼びますか?

これを呼んでいるものを突き止めることは可能ですか?ゾンビをオンにしていますが、発信者が表示されません。

スレッド 1 は次のとおりです。

スレッド 1 のクラッシュ

他にクリック可能な唯一の行は、AFNetworking からのこの行です ( [runloop run])。AFNetworking ポッドをアップグレードしました。

+ (void)networkRequestThreadEntryPoint:(id)__unused object {
    @autoreleasepool {
        [[NSThread currentThread] setName:@"AFNetworking"];

        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
        [runLoop run];
    }
}

編集: 上記のブレークポイント@autoreleasepoolはヒットさえしませんでした。別のスレッドで同じクラッシュが発生したときにコードでこれを見つけました(前回は見ませんでした):、archiveSuccessful = line

- (void)archiveContent:(BOOL)changeNotification userInfo:(NSDictionary *)userInfo {
    BOOL archiveSuccessful;
    @synchronized(self) {
        archiveSuccessful = [NSKeyedArchiver archiveRootObject:self.contentDictionary toFile:self.filePath];
    }
    if (archiveSuccessful) {
        if(changeNotification && self.contentChangedNotificationName) {
            [[NSNotificationCenter defaultCenter] postNotificationName:self.contentChangedNotificationName object:nil userInfo:userInfo];
        }
    } else {
        NSAssert(NO, @"Saving archive to %@ was not successful", self.filePath);
    }
}

これは

- (void)addObjects:(NSArray *)objects changeNotification:(BOOL)changeNotification {
    [objects enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if([obj conformsToProtocol:NSProtocolFromString(@"DRLocalObject")]) {
            [self addObject:obj changeNotification:NO];
        }
    }];

[self addObject...行からのデバッガーの出力

(lldb) po obj
0x00007fde0ff56770

(lldb) po 0x00007fde0ff56770
140591727208304

編集:

threadMain:Google アナリティクスから呼び出されます。プロジェクトを検索してクイック オープンすると、名前の付いたセレクターが表示されないthreadMain:

ここに画像の説明を入力

4

1 に答える 1

1

(これは StackOverflow を介してデバッグするのが非常に難しい種類のバグなので、ここではポインタを示します。)

ほとんどの場合、複数のスレッドでデータ構造を変更しています。詳細を考えると、他のスレッドで列挙しているときに、あるスレッドでドロップするオブジェクトの ivar である配列があると思われます。所有しているオブジェクトの割り当てを解除するか、配列を置き換えることによって、それを削除します。

呼び出しているという事実は@synchronized(self)、このプログラムで危険なスレッドを実行していることを強く示唆しています。現代の ObjC では@synchronized、適切なツールになることはほとんどありません。直接使用している場合NSThread、それはおそらく問題の原因でもあります (AFNetworking はこれをパスするのに十分古いですが、彼らのアプローチをコピーするべきではありません)。並行性を処理するための適切なツールは、GCD ( dispatch_*) またはNSOperationです。

self.contentDictionaryとのすべてのミューテーションself.filePathも同期されていることを確認しましたか。self.contentDictionary配列が含まれている可能性のあるものであるため、特に疑わしいと思います。

ここでアクセサーを正しく使用することを称賛しますが、アクセサーがアトミックでない場合、異なるスレッドでそれらを読み書きすると、一貫性のない状態になる可能性があります。それらをアトミックにしても、完全にスレッドセーフになるわけではありません。GCD のようなものを使用するか、NSOperationアクセスをシリアル化する必要があります。

同じメソッドで呼び出してから通知を投稿するという事実@synchronizedも、やや疑わしいです。通知は、投稿されたのと同じスレッドで同期的に処理されるため、通知オブザーバーは、どのスレッドで呼び出される可能性があるかを認識する必要があります。

AFNetworking 実行ループ処理メソッドでのクラッシュは無意味であることに注意してください。それはあなたに本当のヒントを与えていません。

私はあなたのスレッドに目を向けます。特に、配列 (および特に配列プロパティ) への保護されていないアクセスを探します。また、すべてのアクセスを GCD またはNSOperationではなくでシリアル化するようにしてください@synchronize

于 2014-11-21T21:23:13.247 に答える