Sollte ich noch kopieren/Block_copy die Blöcke unter ARC?
Ich habe gerade stolperte über die folgenden SO-Thema: Warum sollten wir kopieren die Blöcke eher als behalten? was hat der folgende Satz:
Jedoch, wie von iOS 6 Sie behandelt werden als normale Objekte, so dass Sie brauchen keine sorgen zu machen.
War ich echt verwirrt durch diese Aussage, dass ist der Grund, warum ich Frage: ist diese Aussage wirklich bedeuten, dass Objective-C-Entwickler müssen nicht
@property (copy) blockProperties
oder
[^(...){...) {} copy]
kopieren Bausteine und Ihre Inhalte von stack zu heap mehr?
Ich hoffe die Beschreibung die ich gemacht habe, ist klar.
Bitte ausführlich sein.
Ähnliche Fragen
Unter BOGEN, sind Blöcke automatisch kopiert, wenn Sie zugewiesen werden, um ein ivar direkt?.
InformationsquelleAutor der Frage Stanislav Pankevich | 2014-04-28
Du musst angemeldet sein, um einen Kommentar abzugeben.
ARC kopieren wird der block automatisch. Von clang ist Objective-C Automatic Reference Counting Dokumentation:
Also Blöcke, die nur als Argumente der Funktion oder Methode aufruft, kann bleiben stack-Blöcke, aber auch sonst überall, die ARC behält sich das block kopieren block. Umgesetzt wird dies durch den compiler emittiert einen Anruf zu
objc_retainBlock()
die Umsetzung für die:Es ist immer noch eine gute Idee zu erklären, block-Eigenschaften als mit copy-Semantik, da ein block zugewiesen, um eine starke Eigenschaft wird in der Tat kopiert werden. Apple dies empfiehlt:
Beachten Sie, dass seit dieser copy-on-retain-Funktion bereitgestellt wird, durch die ARC ist es nur abhängig von ARC oder ARCLite Verfügbarkeit und nicht anders erfordern eine bestimmte OS-version oder
OS_OBJECT_USE_OBJC
.InformationsquelleAutor der Antwort Matt Stevens
Edit:
Es stellte sich heraus, das die Prüfung der Adressen der "gefangen" - Variablen sind schwer zu interpretieren, und nicht immer angemessen, um herauszufinden, ob ein Block kopiert wurde, um den heap oder befindet sich immer noch auf dem heap. Obwohl die Angabe der Blöcke, die hier gegeben BLOCK-IMPLEMENTIERUNG SPEZIFIKATIONausreichend zu beschreiben, die Fakten, versuche ich einen ganz anderen Ansatz:
Was ist ein Block eigentlich?
Dies ist eine Zusammenfassung der offiziellen Spezifikation BLOCK-IMPLEMENTIERUNG SPEZIFIKATION:
Einem Block existiert, der code (wie eine Funktion) und eine Struktur, die die mehreren Stücke von Daten, flags und Funktion von Zeigern UND einer Variablen Länge der Sektion "erfasste Variablen".
Beachten Sie, dass diese Struktur von privaten und Umsetzung definiert.
Eines Blocks kann definiert werden als Funktion Umfang, in dem diese Struktur erstellt, die in lokalen stack-Speicher, oder es kann definiert werden, in globalen oder statischen Bereich, wo die Struktur ist erstellt, im statischen Speicher.
Einen Block können Sie "import" andere Block-Referenzen, weitere Variablen und
__block
modifizierten Variablen.Wenn ein Block Verweise von anderen Variablen, Sie werden importiert:
Einen Stapel lokale (automatische) Variablen, werden "importiert" bedeutet, dass eine "const " kopieren".
Einen
__block
modifizierten Variablen importiert werden, durch zuweisen von einem Zeiger die Adresse der variable eingeschlossen in einer anderen Struktur.Globale Variablen werden einfach referenziert (nicht "importiert").
Wenn eine variable importiert werden, "erfasst die variable" Leben in der oben genannten Struktur in die variable-Länge Abschnitt. Das ist das "Gegenstück" des in der automatischen Variablen " (das Leben außerhalb des Blocks) hat einen Speicher innerhalb des Blocks Struktur.
Da dieser "erfasst die variable" schreibgeschützt ist, kann der compiler ein paar Optimierungen: zum Beispiel, wir brauchen wirklich nur eine Instanz der erfassten Variablen auf dem heap, wenn wir jemals brauchen, eine Kopie des Blocks.
Den Wert der erfassten Variablen werden gesetzt, wenn der block-literal-Ausdruck sein, der ausgewertet wird. Dies bedeutet auch, dass die Speicherung der erfassten Variablen müssen beschreibbar sein (keine code-Abschnitt).
Die Lebensdauer der aufgezeichneten Variablen, die einer Funktion: mit jedem Aufruf des Blocks erfordert eine neue Kopie dieser Variablen.
Erfassten Variablen in Blöcken, die live auf dem stack werden zerstört, wenn das Programm verlässt die compound-Anweisung des Blocks.
Erfassten Variablen in Blöcken, die Leben auf dem heap, werden zerstört, wenn der block zerstört wird.
Entsprechend der Block-API, Version 3.5:
Zunächst, wenn ein block-literal erstellt wird, wird diese Struktur vorhanden ist, auf dem stack:
Bitte beachten Sie, dass dies für Block Literale.
Gemäß der Objective-C-Erweiterungen zu blockieren,der compiler behandeln Blöcke wie Objekte.
Beobachtungen
Nun, es ist schwierig, Handwerk test-code, die beweist diese Behauptung. So scheint es besser, den debugger verwenden und legen Sie symbolische Haltepunkte an relevanten Funktionen
_Block_copy_internal
undmalloc
(das sollte nur aktiviert werden, nachdem der erste Haltepunkt getroffen wurde)und führen Sie dann geeignete test-code (wie die Ausschnitte unten) und untersuchen, was passiert:
In den folgenden code-snippet erstellen wir einen Block wörtliche und übergeben Sie es als parameter an eine Funktion, die nennt es:
Die Ausgabe ist wie folgt:
Die Adresse des "eingefangen" variable
x0
Ergebnisse deuten stark darauf hin, dass es Leben auf dem Stapel.Wir haben auch ein breakpoint auf
_Block_copy_internal
- jedoch nicht getroffen werden. Dies deutet darauf hin, dass der Block nicht kopiert wurden, werden auf dem heap. Ein weiterer Beweis gemacht werden können mit Instrumenten, die nicht zeigen, Zuweisungen in der Funktionfoo
.Wenn wir nun erstellt und initialisiert ein block variableso scheint es, die Block-Daten-Struktur der original - Block wörtliche - die zunächst noch auf dem Stapel erzeugt, kopiert werden auf den heap:
Diese oben Kopien der block wurde zunächst auf dem Stapel erzeugt. Das kann einfach passieren, wegen ARC und die Tatsache, dass wir ein block-literal auf der rechten hand, und die block variable
block
auf der linken Seite zugewiesen werden, die block-literal - die Ergebnisse in einemBlock_copy
Betrieb. Dies lässt Blöcke erscheinen viel wie normale Objective-C-Objekte.Verrechnungen mit verfolgt Instrumente in diesem ähnlichen code unten
zeigen, dass der Block wird ja kopiert:
Bemerkenswert
Wenn ein block erfasst nicht alle Variablen, ist es wie eine normale Funktion. Dann macht es Sinn, eine Optimierung, wo eine
Block_copy
- Betrieb gibt eigentlich nichts, da es nichts zu kopieren. clang implementiert diese mit der Herstellung solcher Blöcke "global block".Beim senden
copy
zu einem block-variable, und weisen das Ergebnis auf einem anderen block variable, z.B.:copy
eine ganz Billig Betrieb, da der blockblock
hat bereits den zugewiesenen Speicher für die block-Struktur, die freigegeben werden können. Socopy
braucht nicht zu reservieren Speicher wieder.Zurück zu der Frage
Antwort auf die Frage, ob wir explizit einen block kopieren unter bestimmten Umständen, zum Beispiel:
Gut, sobald der block kopiert wurde, egal Wann, und wird dann zugewiesen werden, die Ziel-variable (Block-Variablen), - sollten wir immer sicher, ohne explizit kopieren Sie den block, da ist es schon in den heap.
Im Fall der block Eigenschaftsollte es sicher sein, wenn wir einfach die wright:
dann:
Diese sollten sicher sein, da die Zuordnung eines block-literal (das Leben auf dem stack) die zugrunde liegenden block variable
_completion
kopieren Sie den block auf dem heap.Dennoch, würde ich noch empfehlen die Verwendung von Attribut
copy
- da ist es immer noch vorgeschlagen, die von der offiziellen Dokumentation als best practice und unterstützt auch ältere APIs, wo die Blöcke sich nicht so Verhalten, wie normale Objective-C-Objekte und-wo es kein ARC.Bestehenden system-APIs werden auch kümmern sich um das kopieren eines Blocks, falls erforderlich:
dispatch_async() wird die Kopie für uns. So, wir haben keine sorgen zu machen.
Andere Szenarien sind subtiler:
Aber tatsächlich, das ist sicher: Die block-literal kopiert und zugewiesen der block-variable
block
.Diesem Beispiel sieht vielleicht sogar beängstigend:
Aber es scheint, die Block-literal wird korrekt kopiert werden, wie ein Effekt der Zuweisung des Arguments (der Block), um den parameter (ein
id
) in der MethodearrayWithObject:
die Kopien der Block-literal auf den heap:Darüber hinaus
NSArray
wird behalten das Objekt übergeben als parameter in der MethodearrayWithObject:
. Dies bewirkt, dass ein weiterer AufrufBlock_copy()
da jedoch der Block ist bereits auf dem heap, so wird dieser Aufruf nicht reservieren den Speicher.Dies zeigt, dass eine retain-Nachricht gesendet, um einen Block wörtliche irgendwo in der Umsetzung von
arrayWithObject:
würde auch in der Tat kopieren Sie den Block.Also, wenn wir tatsächlich benötigen, um explizit einen Block kopieren?
Einen block wörtliche - z.B. der Ausdruck:
erstellen die block-Struktur auf dem stack.
So, wir eigentlich müssen eine Kopie zu machen, nur in Fällen, in denen wir müssen den Block auf dem heap, und wenn dies geschieht nicht "automatisch". Es gibt jedoch praktisch keine Szenarien, in denen dies der Fall ist. Auch in Fällen, in denen wir einen Block als parameter an eine Methode, die keine Ahnung hat, dass es einen Block wörtliche und erfordert eine
copy
zunächst (z.B.:arrayWithObject:
), und vielleicht sendet der Empfänger nur ein behalten Nachricht an das Objekt gegeben, in dem parameter, wird der Block kopiert werden auf dem heap ersten.Beispiele, wo wir vielleicht explizit
copy
ist, wo wir nicht zuordnen eines Block-literal-block variable oder einid
und damit die ARC nicht herausfinden, dass es hat zu machen, Kopie der block-Objekt oder zu senden "behalten".In diesem Fall der Ausdruck
ergeben einen autoreleased-Block, dessen Struktur befindet sich auf dem heap.
InformationsquelleAutor der Antwort CouchDeveloper
Mine ursprüngliche Antwort falsch war.
Editiert Antwort ist nicht eine Antwort, sondern eher ein "es ist in der Tat eine gute Frage" zu tun.
Bitte, siehe Matt ' s Antwort für die realen Bezüge warum Sachen die Weise, die es ist.
Nach der Prüfung den folgenden code in iOS7:
Habe ich diese:
Was so ziemlich bedeutet, dass die Blöcke erstellt und zugewiesen und stack-Variablen sind eigentlich schon auf einem Haufen und kopiert Sie nicht auf irgendetwas.
Diese, obwohl, ist nicht gesichert, die durch keine offizielle Quelle, als Sie noch Stand, die Blöcke erstellt werden, auf den stack kopiert werden müssen "beim vorbei gehen".
Teil der Antwort vor, die ich getestet habe, mit der Angabe, welche Dokumente sind im Widerspruch zu der von Beispiel.
Dokument über den übergang zu ARC Staaten:
Und docs über Blöcke und Eigenschaften sagt:
InformationsquelleAutor der Antwort coverback