2011-10-21 4 views
9

関数がメインスレッド上でのみ実行されることを確認するにはどうすればよいですか? (UI要素を更新します)
このような関数は「悪い」と考えられますか?関数がメインスレッドのみで実行されていることを確認する

-(void)updateSomethingOnMainThread { 
if (![[NSThread currentThread] isEqual:[NSThread mainThread]]) 
    [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO]; 
else { 
    // Do stuff on main thread 
} 
} 

私は当初、私はこのようにそれを持っていた、第2の機能を持つ避けるために、このようにそれを書いた:

-(void)updateSomethingOnMainThread_real { 
    // Do stuff on main thread 
} 

-(void)updateSomethingOnMainThread { 
    [self performSelectorOnMainThread:@selector(updateSomethingOnMainThread_real) withObject:nil waitUntilDone:NO]; 
} 
+2

[循環メソッド呼び出しは許可されていますか?](0120-18753) – ughoavgfhw

答えて

3

また、あなたはGrand Central Dispatch APIを使用することができますが、それは非常に便利ではありません。

-(void)updateSomethingOnMainThread { 
    void (^doStuff)(void) = ^{ 
     // stuff to be done 
    }; 

    // this check avoids possible deadlock resulting from 
    // calling dispatch_sync() on the same queue as current one 
    dispatch_queue_t mainQueue = dispatch_get_main_queue(); 
    if (mainQueue == dispatch_get_current_queue()) { 
     // execute code in place 
     doStuff(); 
    } else { 
     // dispatch doStuff() to main queue 
     dispatch_sync(mainQueue, doStuff); 
    } 
} 

同期呼び出しが必要とされていない場合はそうでない場合、あなたがはるかに簡単ですdispatch_async()を呼び出すことができます。

-(void)updateSomethingOnMainThread { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     // do stuff 
    }); 
} 
+1

そのコードを注意してメインスレッドはバインドします。 – NJones

+0

おっと、申し訳ありません。だから私は、現在のキューがメインキューであるかどうかをチェックし、そうでなければそれをディスパッチし、そうであればブロックをその場で実行するべきであると推測します。それは、コードをGCD以外のソリューションよりも複雑にするでしょう:) – ayoy

+0

loganの答えに基づいて、あなたが持っているものはすでに正しいと思います。チェックは必要ありません。 – thelaws

5

私は大きな成功を収めてこの単純な#defineを書いています:

01それはパラメータなしだと仮定し
#define ensureInMainThread(); if (!NSThread.isMainThread) { [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO]; return; } 

そうすれば、あなたの方法は、メインスレッドで実行を保証するためのayoyの方法に基づくGCD実装する代わりに、この

- (void) updateTheThings { 
     ensureInMainThread(); 
     [self.dog setTailWag:YES]; 
     // etc... 
+0

どのようにパラメータを扱いますか? – Moshe

+2

@Mosheどのようなパラメータですか?私は、このメソッドはパラメータを必要としないと思います。 :) – Kjuly

+0

パラメータを持つメソッドを別のスレッドに渡したいのですが? – Moshe

15

のように見える、私は次のGCDベースの使用します(another answer of mineから引き出さ)私のコード内の関数:

void runOnMainThreadWithoutDeadlocking(void (^block)(void)) 
{ 
    if ([NSThread isMainThread]) 
    { 
     block(); 
    } 
    else 
    { 
     dispatch_sync(dispatch_get_main_queue(), block); 
    } 
} 

次に、あなたのコード内の任意の場所にこのヘルパー関数を使用することができます。

runOnMainThreadWithoutDeadlocking(^{ 
    // Do stuff that needs to be on the main thread 
}); 

これにより、どのスレッドがこれを呼び出すにしても、囲まれたブロックで実行されるアクションが常にメインスレッドで実行されることが保証されます。それは少しのコードを追加し、メインスレッド上でどのコードを実行する必要があるかに関してかなり明白です。

+0

+1ブラッド、「デッドロックなし」の名前を簡単に説明できますか?リスクとは何ですか?それを避けないテクニックは何ですか? 'performSelectorOnMainThread'が' waitUntilDone'で 'NO'もデッドロックしていないのですか? –

+2

@ Yar - 私はこれを上記のリンクに解説しています:http://stackoverflow.com/a/5226271/19679 '-performSelectorOnMainThread:'と 'waitUntilDone'がYESに設定されているのに似ている)メイン・キューへの同期ディスパッチを使用すると、メイン・スレッド上ですでに実行中のもので呼び出された場合、デッドロックになります。これは私を驚かせ、上記のヘルパー機能を生み出しました。 '-performSelectorOnMainThread:' waitUntilDone'がYESに設定されていても、この問題はありません。メインキューへの非同期ディスパッチには、デッドロックの問題はありません。 –

関連する問題