NSDefaultRunLoopMode vs NSRunLoopCommonModes

114

Jedes Mal , wenn ich versuche , eine große Datei hinter herunterladen UIScrollView, MPMapViewoder etwas, wird der Download - Prozess, sobald ich Bildschirm berühren iPhone gestoppt. Zum Glück schlägt ein großartiger Blog-Beitrag von Jörn eine alternative Option NSRunLoopCommonModesfür die Verbindung vor.

Das bringt mich dazu, die beiden Modi NSDefaultRunLoopMode und NSRunLoopCommonModes im Detail zu betrachten, aber das Apple-Dokument erklärt es nicht freundlich, außer zu sagen

NSDefaultRunLoopMode

Der Modus für den Umgang mit anderen Eingabequellen als NSConnection-Objekten. Dies ist der am häufigsten verwendete Run-Loop-Modus.

NSRunLoopCommonModes

Objekte, die einer Ausführungsschleife mit diesem Wert als Modus hinzugefügt wurden, werden von allen Ausführungsschleifenmodi überwacht, die als Mitglied der Gruppe der "allgemeinen" Modi deklariert wurden. Weitere Informationen finden Sie in der Beschreibung von CFRunLoopAddCommonMode.

CFRunLoopAddCommonMode

Quellen, Timer und Beobachter werden in einem oder mehreren Run-Loop-Modi registriert und nur ausgeführt, wenn die Run-Loop in einem dieser Modi ausgeführt wird. Allgemeine Modi sind eine Reihe von Run-Loop-Modi, für die Sie eine Reihe von Quellen, Timern und Beobachtern definieren können, die von diesen Modi gemeinsam genutzt werden. Anstatt beispielsweise eine Quelle für jeden bestimmten Run-Loop-Modus zu registrieren, können Sie sie einmal im allgemeinen Pseudomodus der Run-Loop registrieren. Sie wird automatisch in jedem Run-Loop-Modus im Common-Mode-Set registriert. Wenn ein Modus zu dem Satz von allgemeinen Modi hinzugefügt wird, werden alle Quellen, Zeitgeber oder Beobachter, die bereits für den gemeinsamen Pseudomodus registriert sind, ebenfalls zu dem neu hinzugefügten gemeinsamen Modus hinzugefügt.

Kann jemand bitte die beiden in menschlicher Sprache erklären?

Stkim1
quelle

Antworten:

204

Eine Ausführungsschleife ist ein Mechanismus, mit dem das System schlafende Threads aktivieren kann, damit sie asynchrone Ereignisse verwalten können. Normalerweise gibt es beim Ausführen eines Threads (mit Ausnahme des Hauptthreads) die Möglichkeit, den Thread in einer Ausführungsschleife zu starten oder nicht. Wenn der Thread eine Art oder einen lang laufenden Vorgang ohne Interaktion mit externen Ereignissen und ohne Zeitgeber ausführt, benötigen Sie keine Ausführungsschleife. Wenn Ihr Thread jedoch auf eingehende Ereignisse reagieren muss, sollte er an eine Ausführungsschleife angehängt werden Wecken Sie den Thread auf, wenn neue Ereignisse eintreffen. Dies ist bei NSURLConnectiongenerierten Threads der Fall , da sie nur bei eingehenden Ereignissen (aus dem Netzwerk) aktiviert werden.

Jeder Thread kann mehreren Ausführungsschleifen oder einer bestimmten Ausführungsschleife zugeordnet sein, die so eingestellt werden kann, dass sie in verschiedenen Modi funktioniert. Ein "Run-Loop-Modus" ist eine Konvention, die vom Betriebssystem verwendet wird, um einige Regeln für die Zustellung bestimmter Ereignisse festzulegen oder diese zu sammeln, um sie später zu übermitteln.

Normalerweise werden alle Ausführungsschleifen auf den "Standardmodus" gesetzt, der eine Standardmethode zum Verwalten von Eingabeereignissen festlegt. Beispiel: Sobald ein Ereignis zum Ziehen mit der Maus (Mac OS) oder Berühren (unter iOS) auftritt, wird der Modus für diese Ausführungsschleife auf Ereignisverfolgung eingestellt. Dies bedeutet, dass der Thread bei neuen Netzwerkereignissen nicht geweckt wird. Diese Ereignisse werden jedoch später übermittelt, wenn das Benutzereingabeereignis beendet und die Ausführungsschleife wieder in den Standardmodus versetzt wird. Offensichtlich ist dies eine Entscheidung der Betriebssystemarchitekten, Benutzerereignissen anstelle von Hintergrundereignissen Vorrang einzuräumen.

Wenn Sie den Run-Loop-Modus für Ihren NSURLConnectionThread mithilfe von ändern möchten, scheduleInRunLoop:forModes:können Sie den Thread einem speziellen Run-Loop- Modus und nicht der spezifischen Standard-Run-Loop zuweisen . Der spezielle aufgerufene Pseudomodus NSRunLoopCommonModeswird von vielen Eingabequellen einschließlich der Ereignisverfolgung verwendet. Wenn Sie beispielsweise die NSURLConnectionInstanz dem allgemeinen Modus zuweisen , werden die Ereignisse zusätzlich zum "Standardmodus" dem "Verfolgungsmodus" zugeordnet. Ein Vorteil / Nachteil des Zuordnens von Threads NSRunLoopCommonModesbesteht darin, dass der Thread nicht durch Berührungsereignisse blockiert wird.

Zu den allgemeinen Modi können neue Modi hinzugefügt werden, dies ist jedoch eine recht einfache Operation.

Abschließend möchte ich einige Anmerkungen hinzufügen:

  • Normalerweise müssen wir eine Reihe von Bildern oder Miniaturansichten verwenden, die aus dem Netzwerk mit einer Tabellenansicht heruntergeladen wurden. Wir denken möglicherweise, dass das Herunterladen dieser Bilder aus dem Netzwerk während des Bildlaufs in der Tabellenansicht die Benutzererfahrung verbessern könnte (da wir die Bilder beim Bildlauf sehen könnten), dies ist jedoch nicht vorteilhaft, da die Fließfähigkeit des Bildlaufs stark leiden kann. In diesem Beispiel NSURLConnectionsollte keine Run-Schleife verwendet werden. Es ist besser, die UIScrollViewDelegate-Methoden zu verwenden, um zu erkennen, wann das Scrollen beendet ist, und dann die Tabelle zu aktualisieren und neue Elemente aus dem Netzwerk herunterzuladen.

  • Sie können die Verwendung von GCD in Betracht ziehen, um Ihren Code vor Problemen mit der Verwaltung von Ausführungsschleifen zu schützen. Im obigen Beispiel können Sie Ihre Netzwerkanforderungen zu einer benutzerdefinierten seriellen Warteschlange hinzufügen.

viggio24
quelle
9
Lieber Viggio24, vielen Dank für diese saubere und präzise Erklärung. Ich würde Apple bitten, Ihren Kommentar in den API-Leitfaden aufzunehmen. ;)
Stkim1
7
Die Antwort von viggio24 ist perfekt. Für Interessenten möchte ich darauf hinweisen, dass Session 208 (Netzwerk-Apps für iPhone OS, Teil 2) von WWDC 2010 ein Intro zu Run-Loops enthält. Wenn Sie interessiert sind, schauen Sie. Ich hoffe es hilft.
Lorenzo B
19
Nur eine Anmerkung für mich: NSRunLoopCommonModesErmöglicht Timer-Ereignisse beim Scrollen UIScrollView. NSDefaultRunLoopModeTimer beim Scrollen verhindern.
Eonil
2
Ich fand den Kommentar zum Update der Bildlaufansicht sehr interessant, da er ein sehr herausforderndes Thema erwähnt. Nur um weitere Details hinzuzufügen: Wenn Sie einen Modus für eine NSURLConnection festlegen, wirkt sich dies nur auf die Ausführung der Delegatenrückrufe aus. Ich verstehe, dass das Aktualisieren der scrollView hier zu einem Leistungsproblem führen kann, aber warum geschieht dies? Wenn die Antwort lautet, dass das Bild in den Speicher geladen werden muss, können Sie dies tun, indem Sie in einen grafischen Kontext im Hintergrund schreiben und anschließend die Hauptthread-Ebene Ihrer Ansicht aktualisieren. klingt das vernünftig
Nebillo