2011-01-07 7 views
1

Aus irgendeinem Grund, wenn ich auf ein beliebiges Steuerelement drücke (klicke und halte), friert der NSTimer in meiner App ein und zündet nicht, bis ich die Maustaste loslasse. Es feuert einfach nicht, während ich die Maus gedrückt habe. Das ist für kurze Zeit in Ordnung, aber es friert auch ein, wenn ich ein Popup-Menü geöffnet habe oder eine Combobox heruntergefallen ist.NSRunLoop friert mit NSTimer und einem beliebigen Eingang ein

Ich bin mir nicht sicher, ob es etwas gibt, das ich vermisst habe, aber es scheint, dass dies ein inkorrektes Verhalten ist.

Ich möchte in der Lage sein, auf den Abwärtspfeil einer NSPopUpButtonCell (oder klicken und halten Sie eine NSTableView) ohne den gesamten NSTimer Einfrieren (die eine NSView neu gezeichnet) klicken können.

Alle Kommentare/Vorschläge wären willkommen.

Der NSTimer wird dem currentRunLoop mit dem Modus NSDefaultRunLoopMode hinzugefügt.

Antwort

8

Während die Maus inaktiv ist, befindet sich die Laufschleife in der NSEventTrackingRunLoopMode. Daher wird jedes Ereignis, das nicht in der EventTracking-Ereigniswarteschlange empfangen wird, nicht gewartet, bis die Runloop in den entsprechenden Modus zurückkehrt.

Der Weg dahin ist, den Runloop für beide Modi den Timer hinzuzufügen (Standard und Ereignisverfolgung).

+0

Das hat perfekt funktioniert. Danke für Ihre Hilfe! Als eine Nebenfrage sollten Verbindungen (NSInputStream/NSOutputStream) im NSConnectionReplyMode sein? – David

0

Angenommen, Sie haben nur einen Thread in Ihrer Anwendung, was Sie beschrieben haben, wird perfekt erwartet. Standardmäßig werden NSTimer zu der aktuellen NSRunLoop hinzugefügt, die in Ihrem Fall auch für die Interaktion mit der Benutzeroberfläche zuständig ist. Wenn es mit der Interaktion mit der Benutzeroberfläche zusammenhängt, kann es Ihren Timer nicht überprüfen und "feuern".

Eine Lösung ist Multithreading zu verwenden, um diese Verbindung zu vermeiden. Hier ist eine schöne Blog-Post über dieses Thema: http://blog.narent.com/?p=21

EDIT: Siehe Daves Beitrag für eine Alternative (und elegante IMO) Lösung

Siehe auch:

+0

Multithreading sicher ist * eine * Lösung, aber es ist nicht die einzige. –

+0

Danke für die Korrektur, gute Sachen zu wissen. Ihre Lösung scheint viel schöner! – Sam

+0

Danke. Das Ausführen des Timers in einem zweiten Thread ist eine großartige Option. Der Hauptgrund dafür * macht * es nicht, wenn Sie den Timer verwenden, um UI-Updates auszulösen, da Sie die UI nicht von etwas anderem als dem Haupt-Thread aktualisieren sollen, für den dieser Typ sie anscheinend verwendet (obwohl Sie könnte zurück zum Hauptthread ich denke ...). –

8

Statt das Hinzufügen von zwei oder mehr Timer zu verschiedenen runloops oder Multithreading verwenden (da Sie nicht dann in der Lage sein, die Benutzeroberfläche von einem anderen Thread zu aktualisieren) einfach den Timer zu den NSRunLoopCommonModes hinzufügen:

NSTimer *myTimer = [NSTimer timerWithTimeInterval:RefreshInterval target:self selector:@selector(doWork) userInfo:nil repeats:YES]; 
    [[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes]; 
+0

perfekt - das löste ein Problem für mich, wenn UI-Thread mit Animation beschäftigt war –