4

メソッドの先頭にコードをドロップして、メソッドを強制的にメイン スレッドでのみ実行する簡単な方法が必要です (メソッドが UI 要素を更新するため)。

現在、私は次のようなものを持っています:

 if (![NSThread isMainThread]){
    [self performSelectorOnMainThread:_cmd withObject:_results waitUntilDone:NO];
    return;
}

しかし、メソッドの引数を入力せずに、これをマクロに含める方法が必要です。現在のメソッドに渡されたパラメーターのリストを反復処理し、NSInvocation などを作成する方法が必要なようです。何かご意見は?

4

5 に答える 5

5

これは機能しますか?

#define dispatch_main($block) (dispatch_get_current_queue() == dispatch_get_main_queue() ? $block() : dispatch_sync(dispatch_get_main_queue(), $block))

これは、メインスレッドからも呼び出す場合にも機能します。ボーナスです。非同期呼び出しが必要な場合は、dispatch_asyncの代わりにを使用してdispatch_syncください。

于 2012-06-13T00:19:16.243 に答える
3

別のスレッドでメソッドを再呼び出しするのではなく、を使用して、機密性の高いコードだけがメインスレッドにあることを確認することdispatch_sync()をお勧めします。これは、 「メインスレッドでタスクを実行するGCD」に対するBrad Larsonの回答のdispatch_get_main_queue()ように、関数で簡単にラップできます。

彼の手順は基本的にあなたがすでに持っているものと同じですが、違いはコードがブロックに入れられ、必要に応じて呼び出されるか、キューに入れられることです。

if ([NSThread isMainThread])
{
    blockContainingUICode();
}
else
{
    dispatch_sync(dispatch_get_main_queue(), blockContainingUICode);
}

必要に応じて、これを問題なくマクロに変換することもできます。

ブロック自体を作成するのに、多くの変更は必要ありません。UIコードが次のようになっている場合:

[[self textLabel] setText:name];

[[self detailTextLabel] setText:formattedDollarValue];

[[self imageView] setImage:thumbnail];

エンキューするブロックに入れると、次のようになります。

dispatch_block_t blockContainingUICode = ^{

    [[self textLabel] setText:mainText];

    [[self detailTextLabel] setText:detailText];

    [[self imageView] setImage:thumbnail];
};
于 2012-06-13T00:16:23.300 に答える
1

そのようなメソッドから動的NSInvocationを作成するために私が知っている唯一の方法は、メソッドの引数がva_listである必要があることです。

現在のメソッドのパラメーターを配列として取得できる必要があります(配列をループしてパラメーターをNSInvocationに追加できるようにするため)。これが可能かどうかはわかりません( )。

于 2012-06-13T00:04:54.597 に答える
0

これがあなたが探しているものだと思います:

- (void)someMethod
{
    // Make sure the code will run on main thread

    if (! [NSThread isMainThread])
    {
        [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:YES];

        return;
    }

    // Do some work on the main thread
}
于 2013-12-04T14:10:55.023 に答える