2010-11-20 6 views
5

Ereignisverfolgung in UIScrollview blockiert den Hauptthread. Ich verwende den Haupt-Thread, um einen Timer auszuführen, der eine Animation antreibt - das Ergebnis ist, dass jede Benutzerinteraktion mit der scrollbaren Ansicht (Ziehen nach oben oder unten usw.) die Animation (die auf dem Haupt-Runloop läuft) zum Einfrieren bringt. Gibt es einen Weg dahin?Die Ereignisverfolgung in UIScrollView blockiert den Hauptthread. Irgendwelche Korrekturen?

Ich habe versucht, RTFM über NSRunloop (CFRunLoopAddCommonMode et al), aber es ist ziemlich knapp, führt mich zu glauben, dass Basteln mit Ereignisprioritäten/Thread-Prioritäten besser vermieden wird. Jeder hat einen Einblick?

+1

Sie können nur UI-Sachen im Hauptthread machen - also würde das Durcheinander mit Thread-Prioritäten nicht zutreffen. Ich bin neugierig - weißt du, ob die NSTimers aufhören zu feuern oder die Timer feuern, aber weigere dich, die Änderungen, die du in der Animation machst, anzuwenden? Ist die Animation * an * der UIScrollView oder * innerhalb * der Scrollansicht? d. h., versuchen Sie, das gleiche zu animieren und zu ändern, das das scrollview scrolling versucht zu ändern? (Scroll-Ansicht, etc.)? – Brad

+0

Danke, Brad - was ich (wahrscheinlich gefährlich) gehofft hatte, war das Hinzufügen des EventTracking-Modus zum Haupt-Runloop, wodurch er gleichzeitig mit dem EventTracking-Runloop weiterlaufen konnte. Die Animation, die blockiert wird, wird tatsächlich in einer anderen Ansicht als der mit der Bildlaufansicht ausgeführt. Um Ihre andere Frage zu beantworten, hört der NSTimer auf, vollständig zu feuern. Es scheint vollständig blockiert zu sein durch das Geschäft mit höherer Priorität beim Verfolgen der Benutzerereignisse auf dem (nicht verwandten) UIScrollView. –

Antwort

16

Statt eines NSTimer der statischen Konstruktoren verwenden, um den Timer-Objekt zu erstellen und es wie folgt manuell planen:

NSTimer *timer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:delayInSeconds] interval:0 target:yourObject selector:yourSelector userInfo:nil repeats:NO]; 
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes]; 
[timer release]; 

Ihre paramters zu initWithFireDate: wird ganz natürlich anders, zumal es klingt wie Sie‘ Verwenden Sie einen Wiederholungstimer. Ich denke, dass Sie die Grundidee sehen können.

Beim Scrollen wechselt die Run-Schleife in einen Modus, der die Ausführung von "Standardmodus" -Tasks verhindert. Die statischen NSTimer-Funktionen planen alle in den Standardmodus, weshalb sie beim Scrollen nicht ausgelöst werden. Wenn Sie den Timer manuell planen, können Sie den Modus festlegen, und NSRunLoopCommonModes enthält den beim Scrollen verwendeten Ausführungsmodus.

+0

Brilliant! Ich hatte verwendet: \t [[NSRunLoop mainRunLoop] addTimer: SchleifeTimer forMode: [NSRunLoop aktuelleModus]]; das war immer noch blockiert. Deine Korrektur funktioniert perfekt. –

+0

Danke eine Billion! Dieser Fix erhöht die Benutzerfreundlichkeit meiner Lazy-Loading-Tabelle drastisch. – Nailer

0

Eine Idee ist es, den Timer auf einem separaten Thread laufen zu lassen. Wenn der Timer ausgelöst wird, dann muss er auf dem Hauptthread laufen.

Edit:

Ah ja, ich habe ganz vergessen, wie UIScrollView Blöcke so ziemlich alles. Eine andere Idee (wenn auch sehr hässlich) besteht darin, zu überprüfen, ob der Zeitgeber während der Delegiertenmethoden (d. H. -scrollviewDidScroll usw.) von UIScrollView ausgelöst wurde. Es ist wirklich eine Art Hack, aber es ist im Grunde die einzige Art, wie mir bewusst ist, dass ich während des Scrollens Code ausführen kann.

+0

Danke, ja, ich habe eigentlich schon meinen Animationstimer auf dem Hauptthread. Es sieht so aus, als würde das Verfolgen von Benutzerereignissen im Hintergrund eine höhere Priorität haben als der Hauptthread. Wenn also etwas kontinuierlich (wie Scrollen) passiert, blockiert es den Hauptthread für eine lange Zeit ... –

+0

@Andy Milburn: Siehe Bearbeiten für eine andere Idee. –

Verwandte Themen