2012-04-09 9 views
3

Ich habe einige Probleme mit^Blöcke in Objective-C. Ich versuche, eine Instanzvariable innerhalb eines Blocks zu setzen - ich habe einige Apple-Dokumentationen zu diesem Thema gelesen und ich habe das Gefühl, alles versucht zu haben. Zugriff auf eine Eigenschaft von einem^-Block verursacht albernes Verhalten

@interface MyClass 
{ 
    // I have tried all possible combinations using __weak, __strong and __block. 
    __weak __block NSMutableArray *filenames; 
} 

// *.m 
static ASIFormDataRequest *g_request = nil; 

@implementation MyClass 
-(void) funnymethod 
{ 
    filenames = [NSMutableArray array]; 
    [filenames addObject:@"This is a string."]; 
    NSLog(@"%@", filenames); 

    g_request = [InitializerClass initializeRequest]; 
    [g_request setCompletionBlock:^ 
    { 
     filenames = [NSMutableArray array]; 
     [filenames addObject:@"This is another string."]; 
     NSLog(@"%@", filenames); 
    }]; 

    [g_object startASynchronous]; 
} 
@end 

Der obige Code gibt die folgende Ausgabe: ("Dies ist ein String.") (null)

Das saugt. Also habe ich verschiedene Kombinationen von __weak, __strong und __block versucht - und alles andere gibt die folgende Ausgabe: ("Dies ist eine Zeichenfolge.") ("Dies ist eine andere Zeichenfolge.") ABER! Es gibt eine massive aber. Der Abschlussblock wird nie verlassen. Der Aktivitätsindikator in der oberen Leiste, der eine offene Verbindung anzeigt, dreht sich weiter und der Bildschirm reagiert nicht mehr.

Wie kann ich das Dateinamen-Objekt aus dem Block erfolgreich setzen? Danke im Voraus.

+0

Was passiert, wenn Ihr Fertigstellungsblock vollständig leer ist? Ich denke, das Problem mit dem ASIFormDataRequest, das nicht beendet wird, hat nichts damit zu tun, was Sie in diesem Block machen. –

Antwort

4

Was die Qualifikations tun:

__block dieser Qualifier ermöglicht eine Schließung der Wert in der angegebenen Variablen gespeichert zu ändern.

__weak ist eine Referenz auf ein Objekt, das nicht verhindert, dass das Objekt von der Zuweisung freigegeben wird.

__strong ist eine Referenz auf ein Objekt, das verhindert verhindern, dass das Objekt nicht zugewiesen wird.

Was müssen Sie tun:

__weak nicht tut, was Sie wollen, weil es nicht das Array nicht verhindern, dass De-zugewiesen, nachdem der aktuelle Umfang endet. Da Sie einen asynchronen Aufruf ausführen, verhindert nichts, dass die Laufzeit den vom Array verwendeten Speicher zurückfordert, bevor der Block ausgeführt wird.

__strong wird das Objekt über das Ende des aktuellen Bereichs hinaus beibehalten. Das ist, was du willst.

__block ermöglicht es Ihrem Block, die angegebene Variable zu ändern, dies wird jedoch nicht benötigt, wenn auf eine Instanzvariable verwiesen wird, da self automatisch beibehalten wird.

In einer Umgebung mit Referenzzählung wird standardmäßig beibehalten, wenn Sie innerhalb eines Blocks auf ein Objective-C-Objekt verweisen. Dies gilt sogar für , wenn Sie einfach auf eine Instanzvariable des Objekts verweisen. Objekt Variablen, die mit dem Modifikator __block speichertyp markiert sind, werden jedoch nicht beibehalten.

Hinweis: Wenn Sie in einer Umgebung mit Garbage Collection sowohl __weak als auch __block-Modifizierer auf eine Variable anwenden, stellt der Block nicht sicher, dass er am Leben gehalten wird.Wenn Sie einen Block in der Implementierung einer Methode verwenden, sind die Regeln für die Speicherverwaltung von Objektinstanzvariablen subtilen:

Wenn Sie eine Instanz Variable durch Verweis zugreifen, selbst gehalten wird;

Ich denke, Ihr Problem hier liegt (relevante Teile in fett):

Sie können festlegen, dass eine importierte Variable sein wandelbar-das heißt, schreibschreib durch die __block Anwendung Modifikator für den Speichertyp. Der __block-Speicher ist dem register-, auto und statischen Speicher für lokale Variablen ähnlich, schließt sich aber gegenseitig aus.

__block-Variablen leben im Speicher, der zwischen dem lexikalischen Gültigkeitsbereich der Variablen und allen deklarierten Blöcken und Blockkopien oder im lexikalischen Gültigkeitsbereich der Variablen freigegeben ist. Somit wird der Speicher die Zerstörung des Stapelrahmens überleben, wenn Kopien der Blöcke, die innerhalb des Rahmens deklariert sind, über das Ende des Rahmens hinaus existieren (für beispielsweise, indem sie irgendwo für die spätere Ausführung in eine Warteschlange eingereiht werden). Mehrere Blöcke in einem gegebenen lexikalischen Bereich können gleichzeitig eine gemeinsame Variable verwenden.

Als eine Optimierung beginnt der Blockspeicher auf dem Stapel - genau wie Blöcke selbst tun. Wenn der Block mit Block_copy kopiert wird (oder in Objective-C, wenn dem Block eine Kopie gesendet wird), werden die Variablen in den Heap kopiert ( ). Somit kann die Adresse einer __block-Variablen über die Zeit geändert werden.

Es gibt zwei weitere Einschränkungen auf __block Variablen: Sie können nicht mit variabler Länge Arrays, und kann nicht Strukturen sein, die C99 enthalten Arrays variabler Länge.

Statt eines NSMutableArray, versuchen, eine Ebene NSArray

+ (id)arrayWithObject:(id)anObject mit verwenden.

+0

"Array variabler Länge" in [dieser Dokumentation] (https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502 -CH6-SW1) bedeutet nicht "NSMutableArray", es bedeutet ["C99 Array variabler Länge"] (http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html). Du darfst ein '__block NSMutableArray *' haben. (Es mag hier keinen Sinn ergeben, aber es ist erlaubt.) –

+0

@KurtRevis entfernt. – mydogisbox

+0

Sie brauchen auch nicht '__block', um den ivar zu ändern. Zugriffe auf Ivars durchlaufen eine implizite "self" Variable, die vom Block kopiert wird. Effektiv macht der Block 'self> fileNames = newValue'. –