1

OSX 10.5.8ターゲット、32ビットおよびi386ビルド用のXCode3.1.1でのコンパイル。

NSWindowwloopとNSViewvloopで実行されているモーダル実行ループがあります。モーダルループが最初に開始されます。期待どおりに起動、実行、停止します。これが始まりです:

[NSApp runModalForWindow: wloop];

次に、ユーザーがマウスの左ボタンを押すと、次のようになります。

if (ticking == 0) // ticking is set to zero in its definition, so starts that way
{
    ticking = 1; // don't want to do this more than once per loop
    tickCounter = 0;
    cuckCoo = [NSTimer scheduledTimerWithTimeInterval: 1.0f / 10.0f         // 10x per second
                                               target: self                 // method is here in masterView
                                             selector: @selector(onTick:)   // method
                                             userInfo: nil                  // not used
                                              repeats: YES];                // should repeat
}

呼び出しの戻りを確認すると、タイマーオブジェクトが取得され、期待どおりにタイマー呼び出しが行われたことを確認できます。

これで、ドキュメントによると、「cuckCoo」としてグローバルに保存された結果のNSTimerは、現在の実行ループに自動的に追加されるはずです。現在の実行ループは間違いなくモーダルループです。この時点では、他のウィンドウはロックアウトされており、意図したマウスアクションのあるウィンドウのみがメッセージを受信して​​います。

これが呼び出すメソッド「onTick」は非常に単純で(起動できないため)、vloopNSViewコードにあります。これはすべてが行われている場所です。

- (void) onTick:(NSTimer*)theTimer
{
    tickCounter += 1;
    NSLog(@"Timer started");
}

次に、モーダルループを停止するとき(これは正常に機能します)、次のようにします。

[cuckCoo invalidate];
[NSApp stop: nil];
ticking=0;
cuckCoo = NULL;
NSLog(@"tickCounter=%ld",tickCounter);

tickingとtickCounterはどちらもグローバルlongです。

onTick内からNSLogメッセージを取得できません。また、runloopの終了時にNSLogによって報告されるように、tickCounterはゼロのままです。

これはすべてコンパイルされ、正常に実行されます。ダニが出ることはありません。私は完全に途方に暮れています。何かアイデアはありますか?

4

2 に答える 2

3

この問題は、「現在の実行ループは間違いなくモーダルループです」というステートメントに関連しています。Cocoaでは、各スレッドには最大で1つの実行ループがあり、各実行ループはさまざまな「モード」で実行できます。一般的なモードは、デフォルト、イベントトラッキング、およびモーダルです。デフォルトはループが通常実行されるモードですが、イベントトラッキングは通常、マウスのドラッグセッションを追跡するために使用され、モーダルはモーダルパネルなどに使用されます。

-[NSTimercheduledTimerWithTimeInterval:target:selector:userInfo:repeats:]を呼び出すと、タイマーはすぐにスケジュールされますが、モーダル実行ループモードではなく、デフォルトの実行ループモードに対してのみスケジュールされます。この背後にある考え方は、アプリは通常、モーダルパネルの背後で実行し続けるべきではないということです。

モーダル実行ループ中に起動するタイマーを作成するには、-[NSTimer initWithFireDate:interval:target:selector:userInfo:repeats:]を使用してから、-[NSRunLoop addTimer:forMode:]を使用できます。

于 2011-03-22T18:43:19.010 に答える
1

に固有の答え...

[NSApp runModalForWindow: wloop];

...は、モーダル実行ループに入った後です。

NSRunLoop *crl;

    cuckCoo = [NSTimer timerWithTimeInterval: 1.0 / 10
                                      target: self
                                    selector: @selector(onTick:)
                                    userInfo: nil
                                     repeats:YES];
    crl = [NSRunLoop currentRunLoop];
    [crl addTimer: cuckCoo forMode: NSModalPanelRunLoopMode];

(わかりやすくするために個別に取得したcrl)onTickメソッドの形式は次のとおりです。

- (void) onTick:(NSTimer*)theTimer
{
    // do something tick-tocky
}
于 2011-03-22T21:05:50.070 に答える