15

NSRunLoopオブジェクトがあり、それにタイマーとストリームをアタッチします。それは素晴らしい働きをします。それをやめることは、まったく別の話です。

を使用してループを実行します[runLoop run]

を使用してループを停止しようとするとCRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop])、ループが停止しません。CRunLoopRun()代わりにを使用してループを開始すると、機能します。また、呼び出しが正しいスレッド(カスタム実行ループを実行しているスレッド)で行われることを確認しました。私はこれをでデバッグしましたpthread_self()

メーリングリストのアーカイブを見つけました。開発者は、「CRunLoopStop()のrunメソッドを使用してループを開始した場合は、わざわざ使用しないでください」と言っていますNSRunLoop。なぜそうなのか理解できます。通常、同じ関数セットのイニシャライザーとファイナライザーをペアにします。

NSRunLoop「CFに頼る」ことなく、どうやってやめますか?stopにメソッドが表示されませんNSRunLoop。ドキュメントには、3つの方法で実行ループを停止できると書かれています。

  1. タイムアウト値で実行するように実行ループを構成します
  2. 実行ループに使用を停止するように指示しますCFRunLoopStop()
  3. すべての入力ソースを削除しますが、これは実行ループを停止するための信頼性の低い方法です。これは、背後の実行ループに何が詰まっているのかがわからないためです。

さて、私はすでに2を試しましたが、CFを掘り下げる必要があるため、「醜い」感じがします。3.問題外です-非決定論的なコードは好きではありません。

これにより、1が残ります。ドキュメントを正しく理解している場合、既存の実行ループにタイムアウトを「追加」することはできません。新しい実行ループは、タイムアウト付きでのみ実行できます。新しい実行ループを実行しても、ネストされた実行ループしか作成されないため、問題は解決しません。私はまだ古いものにすぐに戻ります、私が止めたかったのと同じです...そうですか?これを誤解したかもしれません。また、タイムアウト値を使用してループを実行したくありません。その場合、CPUサイクルの書き込み(タイムアウト値が低い)と応答性(タイムアウト値が高い)の間でトレードオフを行う必要があります。

これは私が今持っているセットアップです(擬似コードっぽい):

Communicator.h

@interface Communicator : NSObject {
    NSThread* commThread;
}

-(void) start;
-(void) stop;
@end

Communicator.m

@interface Communicator (private)
-(void) threadLoop:(id) argument;
-(void) stopThread;
@end

@implementation Communicator
-(void) start {
    thread = [[NSThread alloc] initWithTarget:self 
                                     selector:@selector(threadLoop:)
                                       object:nil];
    [thread start];
}

-(void) stop {
    [self performSelector:@selector(stopThread)
                 onThread:thread
               withObject:self
            waitUntilDone:NO];
    // Code ommitted for waiting for the thread to exit...
    [thread release];
    thread = nil;
}
@end

@implementation Communicator (private)
-(void) stopThread {
    CRunLoopStop([[NSRunLoop currentRunLoop] getCFRunLoop]);
}

-(void) threadLoop:(id) argument {
    // Code ommitted for setting up auto release pool

    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];

    // Code omitted for adding input sources to the run loop

    CFRunLoopRun();
    // [runLoop run]; <- not stoppable with 

    // Code omitted for draining auto release pools

    // Code omitted for signalling that the thread has exited
}
@endif

どうしようかな?CFをいじるのは一般的/良いパターンですか?私は財団を十分に知りません。CF層への干渉はおそらく危険ですか(メモリの破損、不整合、メモリリークに関して)?私が達成しようとしていることを達成するためのより良いパターンはありますか?

4

1 に答える 1

9

あなたは元気です。Foundationで目標を達成できない場合でも、CoreFoundationを使用しても問題はありません。CoreFoundationはCであるため、メモリ管理を台無しにするのは簡単ですが、使用CFRunLoopするよりも本質的な危険はありませんNSRunLoop場合によっては、より安全な場合もありますCFRunLoop。APIはスレッドセーフですが、NSRunLoopそうではありません)。

を停止したい場合はNSRunLoop、を使用して実行できますrunMode:beforeDate:runMode:beforeDate:入力ソースが処理されるとすぐに戻るので、タイムアウト日に達するまで待つ必要はありません。

 NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
 NSDate *date = [NSDate distantFuture];
 while ( !runLoopIsStopped && [runLoop runMode:NSDefaultRunLoopMode beforeDate:date] );

次に、実行ループを停止するには、に設定runLoopIsStoppedする必要がありますYES

于 2011-12-21T14:03:46.710 に答える