7

Ich bin vertraut mit der __block-Anweisung, die die Variable 'zuweisbar' innerhalb eines Blocks macht. Aber ich sehe, dass wenn einige Objective-C-Features, die Blöcke als Argumente in Methoden verwenden, einige Variablen zuweisbar sind, auch wenn sie nicht mit dieser __block-Anweisung deklariert sind.iOS >> Blöcke >> Ändern der Werte von Variablen außerhalb des Blocks

Hier sind 2 Codes zum Beispiel:

[UIView animateWithDuration:2 animations:^ 
    { 
     self.animatedView.backgroundColor = [UIColor blueColor]; 
     self.animatedView.center = CGPointMake(100, 100); 
    }]; 

(animatedView ist ein einfaches UIView mit einem IBOutlet angeschlossen).

int myInt = 10; 
    NSMutableString* mString = [NSMutableString stringWithString:@"Mutable Hello"]; 
    NSString* imString = @"Imutable Hello"; 

    void (^myBlock)(void) =^
    { 
     [mString appendString:@" Block"]; //working 
     imString = @"Imutable Hello Block"; //error 
     myInt = 11; //error 
    }; 

Meine Frage ist: Wie komme ich Werte auf die UIView Instanzeigenschaften zuweisen können?

Ich adressiere kein Objekt und ändere es, wie mein mString.

Ich würde erwarten, dass die Eigenschaft 'center' sich wie myInt verhält, da es sich um eine C-Struktur handelt, auf die direkt zugegriffen wird, und nicht um einen Zeiger auf ein Objekt.

Ich würde 'backgroundColor' erwarten, sich wie mein imString zu verhalten, da es ein Zeiger auf ein Objekt ist, das mit einem neuen Objekt zugewiesen wird, oder?

Ich konnte keine befriedigende Erklärung in der Dokumentation finden ... Ich würde mich freuen, wenn jemand einen liefern kann, oder mich zu einem ansprechen.

Antwort

8

Dies ist der Unterschied zwischen Zuweisung und Verwendung. Verwendung als Methodenaufrufe Sie dürfen Methoden für eine Instanz vollständig aufrufen ([mString appendString:@" Block"]; //working), aber Sie können (imString = @"Imutable Hello Block"; //error) nicht zuordnen, ohne die Variablen zu markieren, um dem Compiler mitzuteilen, dass er sie aktivieren soll.

Dieser Code:

self.animatedView.backgroundColor = [UIColor blueColor]; 

ist noch nicht wirklich eine Zuordnung, es ist ein 'versteckter' Methodenaufruf. Punktnotation ist nie eine Aufgabe, es ist syntaktischer Zucker für Methodenaufrufe. Er übersetzt tatsächlich:

[[self animatedView] setBackgroundColor:[UIColor blueColor]]; 

Der Unterschied zwischen den lokalen Variablen zuweisen und den Variablen innerhalb eines Objekts die Stelle im Speicher ist, dass sie an residieren. Im Grunde werden sie lange genug existieren, um nützlich zu sein. Es ist der Unterschied zwischen Daten auf dem Stapel und auf dem Heap.

+0

So ist die Tatsache, dass die oder ‚CGPoint Zentrum‘ ‚Bool versteckt‘ halten ivars hinter ihnen macht keinen Unterschied? Bedeutet das, dass, da sie Eigenschaften sind (auf die über eine Setter-Methode zugegriffen wird), die Art und Weise geändert wird, in der sie im Speicher zugewiesen werden? Ich habe es auch mit einem in meiner Klasse deklarierten Ivar versucht (und keine lokale Variable in der Methode), und es hat auch funktioniert - und es geht keine Methode durch. –

+1

Die Methode ist ein Nebeneffekt (mangels eines besseren Begriffs). Der Unterschied ist der Speicherort. Lokale Variablen werden auf dem Stapel erstellt. Wenn Sie dem Compiler also nicht mitteilen, dass sie auf den Heap kopiert werden sollen, sind sie nicht zugänglich. Der Compiler verwendet auch eine Reihe von "Tricks", wenn Daten innerhalb des Blocks verfügbar gemacht werden (und die Route ist unterschiedlich zwischen Zeigern und Primitiven). Es ist ein tiefgründiges Thema, lesen Sie diesen Thread: http://StackOverflow.com/Questions/15082265/Why-Isa-Block-Variable-Ismoved-to-the-Heap-before-the- Block-ist-kopiert – Wain

+0

Got it. Wain, du bist der Mann! Vielen Dank. –

3

eine Variable innerhalb eines Blocks geändert werden, um zu ermöglichen, verwenden Sie die _ Blockspeichertyp Modifikator-siehe „_block Storage Type“.

__block NSString* imString = @"Imutable Hello"; 

Referenz von apple doc

Die folgenden Regeln gelten für Variablen, die in einem Block verwendet werden:

  1. Auf globale Variablen kann zugegriffen werden, einschließlich statischer Variablen, die innerhalb des EN existieren lexikalischer Geltungsbereich
  2. Parameter, die an den Block übergeben werden, sind zugänglich (genau wie Parameter für eine Funktion). Stack-Variablen (nicht statisch), die für den umgebenden lexikalischen Bereich lokal sind, werden als konstante Variablen erfasst.
  3. Ihre Werte werden am Punkt des Blockausdrucks innerhalb des Programms genommen. In verschachtelten Blöcken wird der Wert vom nächsten umschließenden Bereich erfasst.

  4. Variablen, die lokal für den umschließenden lexikalischen Bereich sind, der mit dem __block-Speichermodifikator deklariert wurde, werden als Referenz bereitgestellt und sind daher änderbar.

  5. Alle Änderungen werden im umschließenden lexikalischen Bereich reflektiert, einschließlich aller anderen Blöcke, die innerhalb desselben umschließenden lexikalischen Bereichs definiert sind. Diese werden im Abschnitt "Der __block-Speichertyp" näher erläutert.

  6. Im lexikalischen Bereich des Blocks deklarierte lokale Variablen, die sich genau wie lokale Variablen in einer Funktion verhalten.

  7. Jeder Aufruf des Blocks stellt eine neue Kopie dieser Variablen bereit. Diese Variablen können wiederum als konstante oder als Referenzvariable in Blöcken verwendet werden, die innerhalb des Blocks eingeschlossen sind.
+0

Sie haben vergessen zu erwähnen, dass dies eine wörtliche Kopie von https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/ ist. TP40007502-CH6-SW2. - Es wäre hilfreicher zu erklären, wie dies auf die jeweilige Frage zutrifft. –

+0

Sound ist gut ... – codercat

+0

Ich lese dieses Dokument ... Und immer noch beantwortet es meine Frage nicht. Welche dieser Regeln bewirkt, dass die UIView-Eigenschaften, die nicht mit __block definiert sind, für die Zuweisung innerhalb des Animationsblocks zugänglich sind. Warum sind meine primitiven Variablen nicht zuweisbar und UIViews primitive Eigenschaften sind; Wie kann ich kein neues Objekt einem Zeiger zuweisen, es sei denn, ich verwende den __block bei der Deklaration und UIView-Eigenschaften können. –

2

In Ihrem ersten Beispiel der Block „fängt“ die Variable Selbst - das ist ein Zeiger auf ein thermotrope Objekt ist. Sie ändern nicht Selbst sich in Ihrem Beispiel, wenn Sie schreiben:

self.someProperty = someValue; 

Selbst ‚s-Wert bleibt immer noch die gleichen - das heißt, er zeigt immer noch auf das gleiche Objekt.

würden Sie Selbst beispielsweise ändern, wenn Sie schreiben:

self = nil; 
+0

OK ... Diese Antwort führt tatsächlich irgendwo hin ... Also macht die Tatsache, dass ich ein Objekt an den Block weitergebe, seine Eigenschaften zuweisbar? Ich habe es getestet, indem ich eine int-Eigenschaft und auch einen int ivar - mit NO __block - zu meiner Klasse hinzugefügt habe, und ich habe gesehen, dass ich ihnen innerhalb des Blocks einen neuen Wert zuweisen kann. Welches Prinzip/welche Regel macht die Eigenschaften/Ivars innerhalb eines Blocks zuweisbar? Während lokale Variablen innerhalb der Methode, in der der Block definiert ist, nicht sind? –

+1

@OhadRegev Die Tatsache, dass Sie eine Methode _ aufrufen können, ist, dass der Zeiger des Empfängers (hier _self_) nicht als eine Auswirkung des Aufrufens einer Methode geändert wird (um die es eigentlich geht, eine Eigenschaft zuzuweisen). Hinweis _self_ ist ein Zeiger, und sein Wert könnte etwas wie "self equal 0xabcd1230' _before_ sein, das eine Methode aufruft, und nach dem Aufruf der Methode ist es immer noch dasselbe:' self ist gleich 0xabcd1230'. – CouchDeveloper

+1

@OhadRegev Die Tatsache, dass die erfassten Variablen (hier der Zeiger _self_, dessen Wert 0xabcd1230 ist) _const_ ist einfach eine _konventionelle_ Konvention, wenn es um Blöcke oder Lambdas geht. Sie könnten auch modifizierbar sein. – CouchDeveloper