Nun, weil es sehr praktisch wäre. Ich würde nicht wissen müssen, was es ist, solange ich die richtige Syntax habe und es sich wie ein NSObject verhält.
Gurghet
5
Wenn Sie nicht wissen, was es ist, woher wissen Sie, dass es sehr praktisch wäre?
Stephen Canon
5
Sie sollten sie nicht verwenden, wenn Sie nicht wissen, was sie sind :)
Richard J. Ross III
5
@ Moshe hier sind einige Gründe, die mir in den Sinn kommen. Blöcke sind einfacher zu implementieren als eine vollständige Delegatenklasse, Blöcke sind leichtgewichtig und Sie haben Zugriff auf Variablen, die sich im Kontext dieses Blocks befinden. Event Callbacks können effektiv mit Blöcken durchgeführt werden (cocos2d verwendet sie fast ausschließlich).
Richard J. Ross III
2
Nicht vollständig verwandt, aber da sich einige Kommentare über die "hässliche" Blocksyntax
Mit xCode 4.4 oder neuer müssen Sie nicht synthetisieren. Das wird es noch prägnanter machen. Apple Doc
Eric
wow, das wusste ich nicht, danke! ... obwohl ich es oft tue@synthesize myProp = _myProp
Robert
7
@ Robert: Sie haben wieder Glück, denn ohne @synthesizedie Standardeinstellung zu setzen, tun Sie @synthesize name = _name;stackoverflow.com/a/12119360/1052616
Eric
1
@CharlieMonroe - Ja, Sie haben wahrscheinlich Recht, aber benötigen Sie keine Dealloc-Implementierung, um die Block-Eigenschaft ohne ARC auf Null zu setzen oder freizugeben? (Es ist schon eine Weile her, seit ich Nicht-ARC verwendet habe)
Robert
1
@imcaptor: Ja, es kann zu Speicherverlusten führen, falls Sie es nicht im Dealloc freigeben - genau wie bei jeder anderen Variablen.
Charlie Monroe
210
Hier ist ein Beispiel, wie Sie eine solche Aufgabe erfüllen würden:
#import <Foundation/Foundation.h>typedefint(^IntBlock)();@interface myobj :NSObject{IntBlock compare;}@property(readwrite, copy)IntBlock compare;@end@implementation myobj
@synthesize compare;-(void)dealloc
{// need to release the block since the property was declared copy. (for heap// allocated blocks this prevents a potential leak, for compiler-optimized // stack blocks it is a no-op)// Note that for ARC, this is unnecessary, as with all properties, the memory management is handled for you.[compare release];[super dealloc];}@endint main (){@autoreleasepool{
myobj *ob =[[myobj alloc] init];
ob.compare =^{return rand();};NSLog(@"%i", ob.compare());// if not ARC[ob release];}return0;}
Das einzige, was sich ändern müsste, wenn Sie die Art des Vergleichs ändern müssten, wäre das typedef int (^IntBlock)(). Wenn Sie zwei Objekte übergeben müssen, ändern Sie dies in: typedef int (^IntBlock)(id, id)und ändern Sie Ihren Block in:
^(id obj1, id obj2){return rand();};
Ich hoffe das hilft.
BEARBEITEN 12. März 2012:
Für ARC sind keine spezifischen Änderungen erforderlich, da ARC die Blöcke für Sie verwaltet, solange sie als Kopie definiert sind. Sie müssen die Eigenschaft in Ihrem Destruktor auch nicht auf Null setzen.
// Here is a block as a property://// Someone passes you a block. You "hold on to it",// while you do other stuff. Later, you use the block.//// The property 'doStuff' will hold the incoming block.@property(copy)void(^doStuff)(void);// Here's a method in your class.// When someone CALLS this method, they PASS IN a block of code,// which they want to be performed after the method is finished.-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater;// We will hold on to that block of code in "doStuff".
Hier ist Ihre .m-Datei:
-(void)doSomethingAndThenDoThis:(void(^)(void))pleaseDoMeLater
{// Regarding the incoming block of code, save it for later:
self.doStuff = pleaseDoMeLater;// Now do other processing, which could follow various paths,// involve delays, and so on. Then after everything:[self _alldone];}-(void)_alldone
{NSLog(@"Processing finished, running the completion block.");// Here's how to run the block:if( self.doStuff != nil )
self.doStuff();}
Achten Sie auf veralteten Beispielcode.
Machen Sie mit modernen Systemen (2014+) das, was hier gezeigt wird. So einfach ist das.
Vielleicht solltest du auch sagen, dass es jetzt (2016) in Ordnung ist, strongstatt zu verwenden copy?
Nik Kov
Können Sie erklären, warum die Eigenschaft in den nonatomicmeisten anderen Fällen, in denen Eigenschaften verwendet werden, nicht anders sein sollte als Best Practices?
Der Nachwelt / Vollständigkeit halber ... Hier sind zwei vollständige Beispiele, wie man diese lächerlich vielseitige "Art, Dinge zu tun" umsetzt. @ Roberts Antwort ist selig präzise und korrekt, aber hier möchte ich auch Wege zeigen, wie man die Blöcke tatsächlich "definiert".
@interfaceReusableClass:NSObject@property(nonatomic,copy)CALayer*(^layerFromArray)(NSArray*);@end@implementationResusableClassstaticNSStringconst* privateScope =@"Touch my monkey.";-(CALayer*(^)(NSArray*)) layerFromArray {return^CALayer*(NSArray*array){CALayer*returnLayer =CALayer.layer
for(id thing in array){[returnLayer doSomethingCrazy];[returnLayer setValue:privateScope
forKey:@"anticsAndShenanigans"];}returnlist;};}@end
Dumm? Ja. Nützlich? Höllen ja. Hier ist eine andere, "atomarere" Art, die Eigenschaft festzulegen ... und eine Klasse, die lächerlich nützlich ist ...
Dies zeigt, wie die Blockeigenschaft über den Accessor (wenn auch innerhalb von init, eine umstrittene heikle Praxis) gegenüber dem "nichtatomaren" "Getter" -Mechanismus des ersten Beispiels festgelegt wird. In beiden Fällen… können die "fest codierten" Implementierungen immer überschrieben werden, pro Instanz .. a lá ..
Außerdem ... wenn Sie eine Blockeigenschaft zu einer Kategorie hinzufügen möchten ... sagen Sie, Sie möchten einen Block anstelle einer alten Aktion / Aktion "Aktion" verwenden ... Sie können einfach zugehörige Werte verwenden, um ... Ordnen Sie die Blöcke zu.
typedefvoid(^NSControlActionBlock)(NSControl*);@interfaceNSControl(ActionBlocks)@property(copy)NSControlActionBlock actionBlock;@end@implementationNSControl(ActionBlocks)-(NSControlActionBlock) actionBlock {// use the "getter" method's selector to store/retrieve the block!return objc_getAssociatedObject(self, _cmd);}-(void) setActionBlock:(NSControlActionBlock)ab {
objc_setAssociatedObject(// save (copy) the block associatively, as categories can't synthesize Ivars.
self,@selector(actionBlock),ab ,OBJC_ASSOCIATION_COPY);
self.target = self;// set self as target (where you call the block)
self.action =@selector(doItYourself);// this is where it's called.}-(void) doItYourself {if(self.actionBlock && self.target == self) self.actionBlock(self);}@end
Wenn Sie jetzt einen Knopf drücken, müssen Sie kein IBActionDrama einrichten . Verknüpfen Sie einfach die Arbeit, die bei der Erstellung zu erledigen ist ...
Dieses Muster kann OVER und OVER auf Cocoa-APIs angewendet werden . Verwenden Sie Eigenschaften, um die relevanten Teile Ihres Codes näher zusammenzubringen , verschlungene Delegierungsparadigmen zu beseitigen und die Leistung von Objekten zu nutzen, die über die bloße Funktion als dumme "Container" hinausgeht.
Alex, tolles assoziiertes Beispiel. Weißt du, ich wundere mich über das Nichtatomare. Gedanken?
Fattie
2
Es ist sehr selten, dass "atomar" das Richtige für eine Immobilie ist. Es wäre sehr seltsam, eine Blockeigenschaft in einem Thread festzulegen und gleichzeitig in einem anderen Thread zu lesen oder die Blockeigenschaft gleichzeitig von mehreren Threads aus festzulegen. Die Kosten für "atomar" gegenüber "nichtatomar" bieten Ihnen also keine wirklichen Vorteile.
Gnasher729
8
Natürlich können Sie Blöcke als Eigenschaften verwenden. Stellen Sie jedoch sicher, dass sie als @property (Kopie) deklariert sind . Zum Beispiel:
In MRC werden Blöcke, die Kontextvariablen erfassen, im Stapel zugewiesen . Sie werden freigegeben, wenn der Stapelrahmen zerstört wird. Wenn sie kopiert werden, wird ein neuer Block im Heap zugewiesen , der später ausgeführt werden kann, nachdem der Stapelrahmen eingefügt wurde.
Dies soll nicht "die gute Antwort" sein, da diese Frage ausdrücklich nach ObjectiveC fragt. Als Apple Swift auf der WWDC14 vorstellte, möchte ich Ihnen die verschiedenen Möglichkeiten zur Verwendung von Blöcken (oder Verschlüssen) in Swift vorstellen.
Hallo, Swift
Sie haben viele Möglichkeiten, einen Block zu übergeben, der der Funktion in Swift entspricht.
Ich habe drei gefunden.
Um dies zu verstehen, empfehle ich Ihnen, dieses kleine Stück Code auf dem Spielplatz zu testen.
func test(function:String->String)->String{return function("test")}
func funcStyle(s:String)->String{return"FUNC__"+ s +"__FUNC"}
let resultFunc = test(funcStyle)
let blockStyle:(String)->String={s in return"BLOCK__"+ s +"__BLOCK"}
let resultBlock = test(blockStyle)
let resultAnon = test({(s:String)->String in return"ANON_"+ s +"__ANON"})
println(resultFunc)
println(resultBlock)
println(resultAnon)
Schnell, optimiert für Verschlüsse
Da Swift für die asynchrone Entwicklung optimiert ist, hat Apple mehr an Schließungen gearbeitet. Die erste ist, dass die Funktionssignatur abgeleitet werden kann, sodass Sie sie nicht neu schreiben müssen.
Greifen Sie über Nummern auf Parameter zu
let resultShortAnon = test({return"ANON_"+ $0 +"__ANON"})
Params Rückschluss auf die Benennung
let resultShortAnon2 = test({myParam in return"ANON_"+ myParam +"__ANON"})
Trailing Closure
Dieser Sonderfall funktioniert nur, wenn der Block das letzte Argument ist. Er wird als abschließender Abschluss bezeichnet
Hier ist ein Beispiel (zusammengeführt mit der abgeleiteten Signatur, um die Swift-Leistung zu zeigen)
let resultTrailingClosure = test {return"TRAILCLOS_"+ $0 +"__TRAILCLOS"}
Schließlich:
Mit all dieser Kraft würde ich Trailing Closure und Typinferenz mischen (mit Benennung zur besseren Lesbarkeit).
PFFacebookUtils.logInWithPermissions(permissions){
user, error in
if(!user){
println("Uh oh. The user cancelled the Facebook login.")}elseif(user.isNew){
println("User signed up and logged in through Facebook!")}else{
println("User logged in through Facebook!")}}
func test(function:String->String, param1:String, param2:String)->String{return function("test"+param1 + param2)}
func funcStyle(s:String)->String{return"FUNC__"+ s +"__FUNC"}
let resultFunc = test(funcStyle,"parameter 1","parameter 2")
let blockStyle:(String)->String={s in return"BLOCK__"+ s +"__BLOCK"}
let resultBlock = test(blockStyle,"parameter 1","parameter 2")
let resultAnon = test({(s:String)->String in return"ANON_"+ s +"__ANON"},"parameter 1","parameter 2")
println(resultFunc)
println(resultBlock)
println(resultAnon)
Antworten:
Wenn Sie denselben Block an mehreren Stellen wiederholen möchten, verwenden Sie den Typ def
quelle
@synthesize myProp = _myProp
@synthesize
die Standardeinstellung zu setzen, tun Sie@synthesize name = _name;
stackoverflow.com/a/12119360/1052616Hier ist ein Beispiel, wie Sie eine solche Aufgabe erfüllen würden:
Das einzige, was sich ändern müsste, wenn Sie die Art des Vergleichs ändern müssten, wäre das
typedef int (^IntBlock)()
. Wenn Sie zwei Objekte übergeben müssen, ändern Sie dies in:typedef int (^IntBlock)(id, id)
und ändern Sie Ihren Block in:Ich hoffe das hilft.
BEARBEITEN 12. März 2012:
Für ARC sind keine spezifischen Änderungen erforderlich, da ARC die Blöcke für Sie verwaltet, solange sie als Kopie definiert sind. Sie müssen die Eigenschaft in Ihrem Destruktor auch nicht auf Null setzen.
Weitere Informationen finden Sie in diesem Dokument: http://clang.llvm.org/docs/AutomaticReferenceCounting.html
quelle
Verwenden Sie für Swift einfach Verschlüsse: Beispiel.
In Ziel-C:
@property (Kopie) nichtig
So einfach ist das.
Hier ist die aktuelle Apple-Dokumentation, in der genau angegeben ist, was verwendet werden soll:
Apple Doco.
In Ihrer .h-Datei:
Hier ist Ihre .m-Datei:
Achten Sie auf veralteten Beispielcode.
Machen Sie mit modernen Systemen (2014+) das, was hier gezeigt wird. So einfach ist das.
quelle
strong
statt zu verwendencopy
?nonatomic
meisten anderen Fällen, in denen Eigenschaften verwendet werden, nicht anders sein sollte als Best Practices?Der Nachwelt / Vollständigkeit halber ... Hier sind zwei vollständige Beispiele, wie man diese lächerlich vielseitige "Art, Dinge zu tun" umsetzt. @ Roberts Antwort ist selig präzise und korrekt, aber hier möchte ich auch Wege zeigen, wie man die Blöcke tatsächlich "definiert".
Dumm? Ja. Nützlich? Höllen ja. Hier ist eine andere, "atomarere" Art, die Eigenschaft festzulegen ... und eine Klasse, die lächerlich nützlich ist ...
Dies zeigt, wie die Blockeigenschaft über den Accessor (wenn auch innerhalb von init, eine umstrittene heikle Praxis) gegenüber dem "nichtatomaren" "Getter" -Mechanismus des ersten Beispiels festgelegt wird. In beiden Fällen… können die "fest codierten" Implementierungen immer überschrieben werden, pro Instanz .. a lá ..
Außerdem ... wenn Sie eine Blockeigenschaft zu einer Kategorie hinzufügen möchten ... sagen Sie, Sie möchten einen Block anstelle einer alten Aktion / Aktion "Aktion" verwenden ... Sie können einfach zugehörige Werte verwenden, um ... Ordnen Sie die Blöcke zu.
Wenn Sie jetzt einen Knopf drücken, müssen Sie kein
IBAction
Drama einrichten . Verknüpfen Sie einfach die Arbeit, die bei der Erstellung zu erledigen ist ...Dieses Muster kann OVER und OVER auf Cocoa-APIs angewendet werden . Verwenden Sie Eigenschaften, um die relevanten Teile Ihres Codes näher zusammenzubringen , verschlungene Delegierungsparadigmen zu beseitigen und die Leistung von Objekten zu nutzen, die über die bloße Funktion als dumme "Container" hinausgeht.
quelle
Natürlich können Sie Blöcke als Eigenschaften verwenden. Stellen Sie jedoch sicher, dass sie als @property (Kopie) deklariert sind . Zum Beispiel:
In MRC werden Blöcke, die Kontextvariablen erfassen, im Stapel zugewiesen . Sie werden freigegeben, wenn der Stapelrahmen zerstört wird. Wenn sie kopiert werden, wird ein neuer Block im Heap zugewiesen , der später ausgeführt werden kann, nachdem der Stapelrahmen eingefügt wurde.
quelle
Disclamer
Dies soll nicht "die gute Antwort" sein, da diese Frage ausdrücklich nach ObjectiveC fragt. Als Apple Swift auf der WWDC14 vorstellte, möchte ich Ihnen die verschiedenen Möglichkeiten zur Verwendung von Blöcken (oder Verschlüssen) in Swift vorstellen.
Hallo, Swift
Sie haben viele Möglichkeiten, einen Block zu übergeben, der der Funktion in Swift entspricht.
Ich habe drei gefunden.
Um dies zu verstehen, empfehle ich Ihnen, dieses kleine Stück Code auf dem Spielplatz zu testen.
Schnell, optimiert für Verschlüsse
Da Swift für die asynchrone Entwicklung optimiert ist, hat Apple mehr an Schließungen gearbeitet. Die erste ist, dass die Funktionssignatur abgeleitet werden kann, sodass Sie sie nicht neu schreiben müssen.
Greifen Sie über Nummern auf Parameter zu
Params Rückschluss auf die Benennung
Trailing Closure
Dieser Sonderfall funktioniert nur, wenn der Block das letzte Argument ist. Er wird als abschließender Abschluss bezeichnet
Hier ist ein Beispiel (zusammengeführt mit der abgeleiteten Signatur, um die Swift-Leistung zu zeigen)
Schließlich:
Mit all dieser Kraft würde ich Trailing Closure und Typinferenz mischen (mit Benennung zur besseren Lesbarkeit).
quelle
Hallo, Swift
Ergänzt die Antwort von @Francescu.
Hinzufügen zusätzlicher Parameter:
quelle
Sie können dem folgenden Format folgen und die
testingObjectiveCBlock
Eigenschaft in der Klasse verwenden.Weitere Informationen finden Sie hier
quelle