Wie speichere ich Blöcke in Eigenschaften in Objective-C?

77

Ich möchte den Objective-C-Block zur späteren Verwendung in einer Eigenschaft speichern. Ich war mir nicht sicher, wie ich es machen sollte, also habe ich ein bisschen gegoogelt und es gibt nur sehr wenige Informationen zu diesem Thema. Aber ich habe es schließlich geschafft, die Lösung zu finden, und ich dachte, dass es sich lohnen könnte, sie für andere Neulinge wie mich zu teilen.

Anfangs dachte ich, ich müsste die Eigenschaften von Hand schreiben, um Block_copy & Block_release zu verwenden.

Zum Glück habe ich herausgefunden, dass Blöcke sind NSObjects und - copy/ - releaseentspricht Block_copy/ Block_release. So kann ich @property (copy)Setter & Getter automatisch generieren.

Piotr Czapla
quelle
1
Mögliches Duplikat von Kann ich Objective-C-Blöcke als Eigenschaften verwenden? Diese Frage ist aktueller als die dortige.
Richard J. Ross III
1
Vollständiger Beispielcode, UP-TO-DATE, einfach für Anfänger erklärt: stackoverflow.com/a/20760583/294884
Fattie
1
Für neue Leser ist diese extrem alte Frage nun glücklicherweise extrem passé. Sie sagen einfach @property (copy) void (^ doStuff) (void); mit nichts mehr oder weniger als Kopie. Heutzutage wird dies an mehreren Stellen im Apfel-Dokument kristallklar (einschließlich des Warum) erklärt. einfacher geht es nicht; Das ist die ganze Antwort. In der Tat ist das ganze Problem nur von historischem Wert, da Sie jetzt nur noch Swift verwenden.
Fattie

Antworten:

135

Bearbeiten: aktualisiert für ARC

typedef void(^MyCustomBlock)(void);

@interface MyClass : NSObject

@property (nonatomic, copy) MyCustomBlock customBlock;

@end

@implementation MyClass

@end

MyClass * c = [[MyClass alloc] init];
c.customBlock = ^{
  NSLog(@"hello.....");
}

c.customBlock();
Dave DeLong
quelle
5
Weiß jemand, warum Sie für Blöcke (nichtatomar, kopieren) und nicht (nichtatomar, beibehalten) verwenden sollten? Normalerweise wird Retain verwendet und ich kann nirgendwo etwas finden, das erklärt, warum Copy für Blöcke verwendet wird.
Steve Potter
29
Ja, Dave, wirklich. Ich kann auch suchen und habe diese auch gesehen. Die Erklärungen waren vage, als würden Sie eine Kopie verwenden, "damit sie den Stapelrahmen tatsächlich überleben". Ich dachte mir, dass das Beibehalten des Objekts das auch tun würde. Keiner erklärte, wie Blöcke gestapelt werden. Ein Kommentar verweist jedoch auf einen Artikel - cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html , der ihn gut erklärt. Siehe unter "Blöcke sind etwas seltsame Objekte". Also vielen Dank!
Steve Potter
Dave - Ich bin mir nicht sicher, ob man besonders "nichtatomar" verwenden sollte. (FWIW - nicht unbedingt korrekt !!! - das neueste Apple-Dokument sagt, Sie sollten "copy" verwenden - Ende der Geschichte.) Es ist schwer zu erkennen, dass die Leistung von Bedeutung sein könnte, und da Ihr Beitrag hier so ziemlich die einzige Referenz der Welt ist Vielleicht ist es eine gefährliche Sache, da draußen zu sein. Irgendwelche Gedanken zu diesem obskuren Thema? Vielen Dank!
Fattie
2
@JoeBlow Sie benötigen Atomicity nur, wenn Sie sich Sorgen machen, den Wert der Eigenschaft gleichzeitig aus mehreren Warteschlangen abzurufen und festzulegen. Sonst spielt es keine Rolle.
Dave DeLong
3
Ich / wir benutzen nonatomicüberall. Es sollte Standard IMO gewesen sein. atomicsorgt für eine größere Binärleistung, eine geringere Leistung (Sperren für alle Accessoren) und scheint Thread-Sicherheit zu versprechen - wenn dies normalerweise auf einer höheren Ebene als bei Eigenschafts-Accessoren gelöst werden muss.
Steven Kramer
101

Alternativ ohne typedef

@property (copy, nonatomic) void (^selectionHandler) (NSDictionary*) ;

Steven Kramer
quelle
20
Da die Syntax so undurchsichtig ist, handelt es sich um eine Blockeigenschaft mit dem Namen "selectionHandler", die ein NSDictionary * -Argument verwendet und void zurückgibt.
Christopher Pickslay
Ich denke nicht, dass es so schwer zu lesen ist, aber ich stimme zu, dass es mit dem typedef besser aussieht. Ich neige dazu, eine Reihe von Typedefs für die Parameter zu schreiben, die ich normalerweise übergeben möchte: PFObjectBlock, PFStringBlock, PFArrayBlock, PFErrorBlock usw.
Besi
Würden id, SEL, IMP weitere Vereinfachungen ermöglichen?
dklt
9

Eine sehr gute Erklärung hierfür finden Sie in der WWDC 2012-Sitzung 712 ab Seite 83. Die richtige Methode zum Speichern eines Blocks unter ARC ist die folgende:

@property(strong) my_block_type work;

Seien Sie vorsichtig mit den Haltezyklen. Eine gute Lösung besteht darin, den Block auf Null zu setzen, wenn Sie ihn nicht mehr benötigen:

self.work = nil;
Jorge Perez
quelle
2
nur mit ARC. Unter MRC ist das falsch. Funktioniert aber copykorrekt sowohl unter MRC als auch unter ARC
newacct
Ich denke nicht, dass Kopie in allen Fällen in MRC gut funktionieren wird, aber vielleicht in den meisten von ihnen
Jorge Perez
Sie haben Recht mit MRC, aber es ist nicht in ARC. Entschuldigung, ich wollte in meinem vorherigen Kommentar ARC sagen.
Jorge Perez
Wirklich interessant, eine Idee, wie ARC es schafft, den Block aus dem Stapel zu entfernen?
MonsieurDart
"__block yourClass * blockSelf = self". Verwenden Sie blockSelf nur innerhalb der Eigenschaft "work".
MasterBeta