6 Stimmen

iOS 4 GCD Fragen

Ich habe mir einige der Präsentationen der WWDC 2010 angesehen und auch die meisten Dokumente zu Blöcken und Gleichzeitigkeit gelesen und habe ein paar Fragen zur Verwendung von Blöcken mit seriellen Warteschlangen in Grand Central Dispatch. Ich habe ein iOS 4 Projekt, das einen Scrollview und ein Wörterbuch mit Bildinformationen hat - Urls zu den Bildern und so weiter. Ich möchte GCD und Blöcke verwenden, um die Bilder herunterzuladen und sie in meinem Scrollview zu platzieren, damit der Hauptthread nicht blockiert wird. Ich habe den folgenden Code geschrieben, der zu funktionieren scheint:

for (NSDictionary* dict in images)
{
     dispatch_async(image_queue, ^{

           NSString* urlString = [dict objectForKey:@"url"];
           NSURL* url = [NSURL URLWithString:urlString];
           NSData* imageData = [[NSData alloc] initWithContentsOfURL:url];
           UIImage* image = [UIImage imageWithData:imageData];
           UIImageView* imageView = // initialize imageView with image;      

           dispatch_async(dispatch_get_main_queue(), ^{
                [self.scrollView addSubview:imageView];
           });
           [imageData release];
      });
}

Ich habe zwei Fragen:

  1. Laut dem Gleichzeitigkeitsleitfaden sollte ich keine Variablen aus dem umschließenden Bereich erfassen, die nicht skalare Typen sind - in meinem Code erfasse ich dict, das ein NSDictionary*-Objekt ist. Wenn ich es nicht erfassen darf, wie sollte ich dann den Code schreiben? Erfasst ein Block nur Variablen aus dem umschließenden Bereich, die tatsächlich verwendet werden?

  2. Was passiert, wenn ich den aktuellen ViewController verlasse, bevor alle Bilder über die serielle Versandwarteschlange abgerufen wurden? Ich glaube nicht, dass sie wissen, dass der ViewController, der sie erstellt hat, weg ist. Was passiert also, wenn sie den Completion-Handler ausführen, bei dem ich die Bildansichten in meine Scrollview auf dem Hauptthread einfüge? Verursacht das einen Fehler oder was? Und wie kann ich alle verbleibenden Operationen in der seriellen Warteschlange abbrechen, wenn mein ViewController verschwindet?

Mit freundlichen Grüßen,

10voto

Kaelin Colclasure Punkte 3885
  1. Dies ist zwar ein unbedeutender Punkt, aber wichtig, um zu verstehen, was der Gleichzeitigkeitsleitfaden Ihnen sagen will: Zeiger sind skalare Typen. Sie können also Zeiger innerhalb von Blöcken einfangen, so viel Sie wollen... ABER Sie müssen sich der Lebensdauer des Speichers bewusst sein, auf den sie zeigen! NSDictionary * ist eine Art von id, und wenn Sie eine id in einem Block referenzieren, übernimmt die Laufzeit die Verantwortung für die Beibehaltung der id, wenn der Block kopiert wird (was durch dispatch_async() geschieht), und gibt sie dann wieder frei, wenn der Block selbst freigegeben wird. Und ja, ein Block erfasst nur Variablen, auf die innerhalb des Blocks verwiesen wird.

  2. Da Sie nun wissen, dass der asynchrone Block ein Retain auf self durchgeführt hat, sollte es klar sein, dass (modulo Speicherverwaltungsfehler) Ihr ViewController nicht "verschwinden" kann, bis der Block fertig ist. Es wird also nicht zum Absturz kommen -- aber Sie haben Recht, wenn Sie anmerken, dass Sie wirklich eine Möglichkeit wollen, diese Art von asynchroner Arbeit abzubrechen, wenn Sie eigentlich nicht mehr vorhaben, die Ergebnisse zu verwenden. Ein einfaches, aber effektives Muster ist es, einen Test an den Anfang des asynchronen Blocks zu setzen, der prüft, ob die Arbeit noch ausgeführt werden soll.

3voto

Da andere Ihre beiden Fragen beantwortet haben, möchte ich mich zu Ihrem Code äußern und Ihnen empfehlen, GCD nicht für Netzwerkabfragen wie Bilder zu verwenden. Das Hauptproblem bei diesen Abfragen ist, dass sie alle gleichzeitig ausgeführt werden. Abhängig von der Anzahl der Downloads können Sie viel zu viele gleichzeitige Verbindungen herstellen, die eine Mobilfunkverbindung lahmlegen können, und der Benutzer könnte am Ende denken, dass etwas nicht stimmt, wenn die Bilder nicht erscheinen, während er um die Verbindung kämpft. wertvoll Netzwerk.

Versuchen Sie, eine NSOperationQueue mit einer maxConcurrentOperationCount Wert von 2 oder 3. Auf diese Weise können Sie eine potenziell unendliche Anzahl von Netzwerkanfragen in eine Warteschlange stellen, aber höchstens einige wenige parallel ausführen lassen. Da Sie auf den Netzwerkstatus des Geräts zugreifen können, können Sie den Wert für WLAN-Verbindungen bedingt auf z. B. 8 erhöhen.

Und das zweite Problem mit GCD ist, dass es ein wenig umständlich ist, ausstehende Operationen abzubrechen. Wenn der Benutzer einen View-Controller eingibt und dann zurückschiebt, halten GCD-Blöcke, je nachdem wie Sie Ihren Code programmiert haben, den View-Controller fest und verhindern, dass er freigegeben wird, und tatsächlich müssen alle Netzwerkoperationen beendet werden, bis der Controller freigegeben werden kann (es macht also keinen Sinn, die Verbindungen in dealloc ).

Ich habe das auf die harte Tour gelernt, indem ich einen Proxy überwachte und schnell in eine Ansicht und zurück ging. Es war wirklich entsetzlich zu sehen, wie die ausstehenden Verbindungen etwa 20 Sekunden lang zusätzliche Schäden an der Netzwerkbandbreite verursacht hat zu meiner ansonsten unauffälligen Bewerbung.

tl;dr verwenden eine Warteschlange für das Netzwerk, GCD für die Bildverarbeitung/Skalierung/GUI-Aktualisierung.

1voto

Artem Oboturov Punkte 4294

@Kaelin Colclasure: für 1. Frage scheint es eher ein Problem der gemeinsamen Zustand in multithreaded Anwendung: für Integral-Typ haben Sie eine Kopie von Wert (die Zeiger auch gilt), aber wenn Sie ein Objekt durch einen Zeiger referenziert verwenden Sie alle Probleme im Zusammenhang mit Abwesenheit von Sperren (Art von Variation auf Objekt Lebensdauer Problem, das Sie hier erwähnt) haben.

0voto

Stephen Darlington Punkte 50435

Hier ist der praktische Unterschied zu Ihrem ersten Punkt:

Wenn ich einen Skalar in einen Block übergebe, der in einer GCD-Warteschlange verwendet wird, dann arbeite ich innerhalb des Blocks mit einer Kopie der ursprünglichen Daten. Änderungen werden außerhalb des Blocks nicht sichtbar sein. (Es gibt hier einige Einschränkungen, die __block Modifikator zum Beispiel, aber im Allgemeinen ist dies korrekt).

Wenn ich, sagen wir mal, an einem NSMutableDictionary in einen Block, wechselt in das Wörterbuch wird außerhalb des Blocks sichtbar sein - dies liegt daran, dass Sie eine Referenz zum Wörterbuch und nahm keine tiefe Kopie.

In beiden Fällen wird die Speicherverwaltung für Sie durchgeführt, d.h. entweder wird die skalare Variable kopiert oder die Objekte werden beibehalten.

Da Sie den Inhalt einer Datenbank nicht ändern können, wird NSDictionary nachdem es initialisiert wurde, werden Sie wahrscheinlich feststellen, dass die Blöcke automatisch das Richtige für Sie tun.

Zum zweiten Punkt: Die Speicherverwaltung erfolgt so gut wie automatisch, es sei denn, Sie müssen mit einer Kopie eines veränderlichen Objekts arbeiten.

0voto

Arun chauhan Punkte 1

Bei der BLE-Entwicklung für iOS gibt es einige Einschränkungen und Anforderungen, die zu beachten sind. Die erste betrifft den iOS-Simulator. Interessanterweise unterstützte der iOS-Simulator früher die Bluetooth-Entwicklung (das WWDC 2012 Bluetooth 101 Video verweist auf diese Funktionalität), aber auf der WWDC 2013 kündigte Apple an, dass der Simulator keine Bluetooth-Unterstützung mehr bieten würde. Oberflächlich betrachtet scheint dies bedauerlich. Allerdings ist die Entwicklung auf einem Gerät mit BLE eine bessere und genauere Erfahrung. Da alle iPhones, die nach dem iPhone 4s (2011) hergestellt wurden, über Bluetooth 4.0 - und damit auch über BLE - verfügen, haben die meisten iOS-Entwickler bereits Geräte, die BLE unterstützen. Wir brauchen die Frage fast gar nicht mehr zu stellen, aber es ist gut zu wissen, wer es nutzen kann, falls Sie eine begrenzte Anzahl von Gerätetypen haben, für die Sie Apps oder BLE-Geräte entwickeln.

Eine weitere wichtige Voraussetzung für die Entwicklung von Core Bluetooth ist, dass Apple die Verantwortung für die Interaktion mit BLE-Geräten größtenteils auf den App-Entwickler überträgt. Nur sehr wenig wird von iOS selbst in Bezug auf die Verwaltung von Bluetooth verwaltet und gepflegt. Eine Sache, die im Betriebssystem verwaltet wird, ist die Verbindung, die in der App "Einstellungen > Bluetooth" angezeigt wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X