0

API の使用方法がわからないため、performSelector:onThreadここでいくつかの提案が必要です。
私の知る限り、 をrunloop呼び出すには が必要なので、作成しperformSelector:onThreadました。しかし、その後、問題が見つかりました。一度電話するとperformSelector:onThreadrunloop停止します。

これが私のテストコードです。runloop は にありfunction kickOffThreadます。

- (void)setCurrentThread
{
    self.thread = [NSThread currentThread];
}

- (void)kickOffThread
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [self performSelector:@selector(setCurrentThread) withObject:nil afterDelay:0];
    while (!threadCheck) {
        NSLog(@"threadCheck = %d", threadCheck);
        [[NSRunLoop currentRunLoop] run];
    }
    [self doSomeCleanUp];
    NSLog(@"thread exit ....");
    [pool release];
}

kickOffThread私は次のように呼びますperformInBackground

   [self performSelectorInBackground:@selector(kickOffThread) withObject:nil];

mainThread で、次の API を呼び出して threadCheck を YES に設定します。正しく呼び出されますが、スレッド ループが突然停止します。

[self performSelector:@selector(signalThreadCheck) onThread:self.thread withObject:nil waitUntilDone:NO];
-(void)signalThreadCheck
{
    NSLog(@" signalThreadCheck ... ");
    threadCheck = YES;
}

端末ログの結果は次のとおりです。「thread exit ....」は出力されません。誰が私に問題がどこにあるのか教えてくれますか?

2013-06-07 15:51:54.827 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.827 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.827 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.836 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.837 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.840 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.844 MBSMapSample[23582:17403] threadCheck = 0
2013-06-07 15:51:54.846 MBSMapSample[23582:17403]  signalThreadCheck ... 
4

2 に答える 2

0

ここで何を達成しようとしているのかを正確に知ることは役に立ちます。なぜなら、メタ質問はNSThreadタスクに適したツールかどうかだからです。多くの場合、GCD が好まれます。

とはいえ、考慮すべきことの 1 つはNSRunLoop、 に入力ソースがあるかどうかです。NSThread次のように new をデタッチする、少し単純化したケースを見てみましょう。

- (void)viewDidLoad
{
    [super viewDidLoad];

    _threadCheck = NO;  // this is an ivar
    [NSThread detachNewThreadSelector:@selector(kickOffThread) toTarget:self withObject:nil];

    double delayInSeconds = 2.0;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        for( uint8_t i = 0; i < 10; i++ )
            [self performSelector:@selector(logSomething) onThread:self.thread withObject:nil waitUntilDone:NO];
        [self performSelector:@selector(signalThreadCheck) onThread:self.thread withObject:nil waitUntilDone:NO];
    });

}

- (void)kickOffThread
{
    _thread = [NSThread currentThread];  // this is an ivar
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    while( !_threadCheck && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] );
    [self doSomeCleanUp];
    printf("thread exit...\n");
}

- (void)doSomeCleanUp {
    printf("cleaning up...\n");
}

- (void)logSomething {
    printf("in background thread...\n");
}

-(void)signalThreadCheck
{
    printf("signalThreadCheck\n");
    _threadCheck = YES;
}

コンソールでは、次のようになります。

cleaning up...
thread exit...

なぜlogSomething呼び出されなかったのですか?生成したバックグラウンド スレッドの実行ループには入力ソースがないため、すぐに終了します。たとえば、入力ソースを追加すると[NSPort port]、生成されたスレッドの実行ループを回転させ続けることができます。

- (void)kickOffThread
{
    _thread = [NSThread currentThread];
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addPort:[NSPort port] forMode:NSRunLoopCommonModes];
    while( !_threadCheck && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] );
    [self doSomeCleanUp];
    printf("thread exit...\n");
}

ここで、以下をコンソールに出力します。

in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
signalThreadCheck
cleaning up...
thread exit...

実行ループの詳細とドキュメントから:

実行ループに入力ソースまたはタイマーが接続されていない場合、このメソッド [run] はすぐに終了します。それ以外の場合は、runMode:beforeDate: を繰り返し呼び出して、NSDefaultRunLoopMode でレシーバーを実行します。つまり、このメソッドは、実行ループの入力ソースとタイマーからのデータを処理する無限ループを効果的に開始します。

于 2013-06-07T10:08:10.723 に答える