web-dev-qa-db-ja.com

iOSはバックグラウンドスレッドを開始します

IOSデバイスに小さなsqlitedbがあります。ユーザーがボタンを押すと、sqliteからデータを取得してユーザーに表示します。

このフェッチ部分は、バックグラウンドスレッドで行いたい(UIメインスレッドをブロックしないため)。私はこれをそうする-

[self performSelectorInBackground:@selector(getResultSetFromDB:) withObject:docids];

取得と少しの処理の後、UIを更新する必要があります。ただし、(良い習慣として)バックグラウンドスレッドからUIの更新を実行しないでください。私はメインスレッドでselectorを次のように呼び出します-

[self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];

しかし、私のアプリは最初のステップでクラッシュします。つまり、バックグラウンドスレッドを開始します。これはiOSでバックグラウンドスレッドを開始する方法ではありませんか?

PDATE 1:[self performSelectorInBackground....の後、このスタックトレースを取得しましたが、何も情報がありません-

enter image description here

PDATE 2:私も、バックグラウンドスレッドを開始しようとしました-[NSThread detachNewThreadSelector:@selector(getResultSetFromDB:) toTarget:self withObject:docids];ですが、それでも同じスタックトレースを取得します。

私が明確にするように、メインスレッドでこの操作を実行すると、すべてがスムーズに実行されます...

PDATEこれは、バックグラウンドから実行しようとしているメソッドです

- (void)getResultSetFromDB:(NSMutableArray *)toProceessDocids
{
    SpotMain *mirror = [[SpotMain alloc] init];
    NSMutableArray *filteredDocids = toProceessDocids;

    if(![gMediaBucket isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForMediaBucketWithDocID:filteredDocids mBucket:gMediaBucket numRes:-1];
    if(![gMediaType isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForMediaType:filteredDocids mediaType:gMediaType numRes:-1];
    if(![gPlatform isEqualToString:@""])
        filteredDocids = [mirror FetchDocIdsForPlatformID:filteredDocids platformId:@"1" numRes:-1];

    self.resultSet = [mirror FetchObjectFromDocid:filteredDocids];
    [filteredDocids release];
    [mirror release];

    [self performSelectorOnMainThread:@selector(showResults) withObject:nil waitUntilDone:NO];
    return;
}
116

performSelectorInBackground:withObject:を使用して新しいスレッドを生成する場合、実行されるセレクターは、新しいスレッドの自動解放プール、実行ループ、およびその他の構成の詳細を設定します。 「NSObjectを使用したスレッドの生成」 AppleのThreading Programming Guideにあります。

ただし、 Grand Central Dispatch を使用した方がよいでしょう。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self getResultSetFromDB:docids];
});

GCDは新しいテクノロジーであり、メモリオーバーヘッドとコード行の点でより効率的です。


更新Chris Nolet へのハットチップ、上記のコードをよりシンプルにし、維持する変更を提案した人Appleの最新のGCDコード例を使用します。

269
Scott Forbes

GCDを使用すると、実際には非常に簡単です。典型的なワークフローは次のようなものです。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        // Perform async operation
        // Call your method/function here
        // Example:
        // NSString *result = [anObject calculateSomething];
                dispatch_sync(dispatch_get_main_queue(), ^{
                    // Update UI
                    // Example:
                    // self.myLabel.text = result;
                });
    });

GCDの詳細については、 Appleのドキュメントはこちら をご覧ください。

8
Pawan Ahire

NSZombieEnabled を有効にして、どのオブジェクトが解放されてからアクセスされるかを確認します。次に、getResultSetFromDB:がそれと関係があるかどうかを確認します。また、docidsの内部に何かがあるかどうか、および保持されているかどうかを確認します。

これにより、問題がないことを確認できます。

4
Nicolas S

Swift 2.xの答え:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        self.getResultSetFromDB(docids)
    }
2
Crashalot

IOSに付属するデフォルトのsqliteライブラリは、SQLITE_THREADSAFEマクロを使用してコンパイルされません。これが、コードがクラッシュする理由かもしれません。

2
Mugunth