Frage

Ist es möglich, Blöcke als Eigenschaften zu haben, um die Standard-Eigenschaft Syntax?

Gibt es Änderungen für ARC

War es hilfreich?

Lösung

@property (nonatomic, copy) void (^simpleBlock)(void);
@property (nonatomic, copy) BOOL (^blockWithParamter)(NSString *input);

Wenn Sie Wiederholung des gleichen Block zu gehen, an mehreren Stellen eine Art verwenden def

typedef void(^MyCompletionBlock)(BOOL success, NSError *error);
@property (nonatomic) MyCompletionBlock completion;

Andere Tipps

Hier ist ein Beispiel dafür, wie man eine solche Aufgabe erfüllen würde:

#import <Foundation/Foundation.h>
typedef int (^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];
}
@end

int main () {
    @autoreleasepool {
        myobj *ob = [[myobj alloc] init];
        ob.compare = ^
        {
            return rand();
        };
        NSLog(@"%i", ob.compare());
        // if not ARC
        [ob release];
    }

    return 0;
}

Nun, das einzige, was zu ändern müssen, wenn Sie die Art der Änderungen benötigt die typedef int (^IntBlock)() vergleichen wäre. Wenn Sie zwei Objekte zu übergeben, ändern Sie ihn auf diese: typedef int (^IntBlock)(id, id) und dem Block ändern:

^ (id obj1, id obj2)
{
    return rand();
};

Ich hoffe, das hilft.

EDIT 12. März 2012:

Für ARC gibt es keine spezifischen Änderungen erforderlich, da ARC werden die Blöcke für Sie so lange verwalten, da sie als Kopie definiert sind. Sie haben nicht die Eigenschaft auf Null in Ihrem destructor, entweder einstellen müssen.

Für mehr lesen, überprüfen Sie bitte dieses Dokument: http://clang.llvm.org/docs/AutomaticReferenceCounting.html

Für Swift, nur Verschlüsse verwenden: Beispiel

.

In Objective-C,

@property (Kopie) void (^ doStuff) (void);

Es ist so einfach.

Apples Dokumentation, dieses Problem vollständig zu erklären:

Apple-doco.

In Ihrer .h-Datei:

// 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 .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();
    }

Beware of out-of-date Beispiel-Code.

Mit modernem (2014+) -Systeme, das tun, was hier gezeigt wird. Es ist so einfach. Hoffe, dass es jemand hilft. Frohe Weihnachten 2013!

Für die Nachwelt / Vollständigkeit halber ... Hier sind zwei volle Beispiele dafür, wie dies zu implementieren lächerlich vielseitig „Art und Weise, Dinge zu tun“. @ Robert Antwort ist wohlig prägnant und richtig, aber hier möchte ich auch Möglichkeiten, um tatsächlich zeigen die Blöcke „definieren“.

@interface       ReusableClass : NSObject
@property (nonatomic,copy) CALayer*(^layerFromArray)(NSArray*);
@end

@implementation  ResusableClass
static  NSString const * 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"];
        }
        return list;
    };
}
@end

Dumme? Ja. Nützlich? Hells ja. Hier ist eine andere, "mehr Atom" Art und Weise die Eigenschaft der Einstellung .. und eine Klasse, die lächerlich nützlich ist ...

@interface      CALayoutDelegator : NSObject
@property (nonatomic,strong) void(^layoutBlock)(CALayer*);
@end

@implementation CALayoutDelegator
- (id) init { 
   return self = super.init ? 
         [self setLayoutBlock: ^(CALayer*layer){
          for (CALayer* sub in layer.sublayers)
            [sub someDefaultLayoutRoutine];
         }], self : nil;
}
- (void) layoutSublayersOfLayer:(CALayer*)layer {
   self.layoutBlock ? self.layoutBlock(layer) : nil;
}   
@end

Dies zeigt die Blockeigenschaft über die Zugriffseinstellung (wenn auch innerhalb init ein debatably dicey Praxis ..) vs das erste Beispiel des „nonatomic“ „Getter“ -Mechanismus. In jedem Fall ... die "fest einprogrammiert" Implementierungen können immer überschrieben, pro Instanz .. a lá ..

CALayoutDelegator *littleHelper = CALayoutDelegator.new;
littleHelper.layoutBlock = ^(CALayer*layer){
  [layer.sublayers do:^(id sub){ [sub somethingElseEntirely]; }];
};
someLayer.layoutManager = littleHelper;

Auch .. wenn Sie einen Block Eigenschaft in einer Kategorie hinzufügen möchten ... sagen Sie einen Block anstatt einige der alten Schule Ziel / Aktion „Aktion“ verwenden möchten ... Sie können nur mit zugehörigen Werte verwenden, gut .. verbinden die Blöcke.

typedef    void(^NSControlActionBlock)(NSControl*); 
@interface       NSControl            (ActionBlocks)
@property (copy) NSControlActionBlock  actionBlock;    @end
@implementation  NSControl            (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 nun einen Button machen, müssen Sie nicht etwas IBAction Drama einrichten .. Nur die Arbeit assoziiert bei der Schöpfung getan werden ...

_button.actionBlock = ^(NSControl*thisButton){ 

     [doc open]; [thisButton setEnabled:NO]; 
};

Dieses Muster angewendet werden über und über Cocoa-API. Verwenden Sie Eigenschaften, um die relevanten Teile des Codes zu bringen näher zusammen , beseitigen gewundene Delegation Paradigmen , und nutzt die Kraft der Objekte über die die gerade die als stumm „Container“.

Natürlich können Sie Blöcke als Eigenschaften nutzen könnten. Aber stellen Sie sicher sind sie deklariert als @property (Kopie) . Zum Beispiel:

typedef void(^TestBlock)(void);

@interface SecondViewController : UIViewController
@property (nonatomic, copy) TestBlock block;
@end

In MRC, Erfassung Blöcke Kontextvariablen zugeordnet sind in Stapel ; sie werden freigegeben, wenn der Stapelrahmen zerstört wird. Wenn sie kopiert werden, wird ein neuer Block in zugewiesen werden heap , die später ausgeführt werden kann, nachdem der Stapelrahmen poped wird.

Disclamer

Dies ist nicht als „die gute Antwort“ bestimmt, da diese Frage für ObjectiveC explizit fragen. Als Apple-Swift am WWDC14 eingeführt, ich mag die verschiedenen Möglichkeiten zur Verwendung Block (oder Verschlüsse) in Swift teilen.

Hallo, Swift

Sie haben viele Möglichkeiten einen Block entspricht Funktion in Swift passieren.

fand ich drei.

Um dies zu verstehen, ich schlage vor, Sie zu Test in Spielplatz dieses kleine Stück Code.

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)

Swift, optimiert für Verschlüsse

Als Swift ist für asynchrone Entwicklung optimiert, arbeitete von Apple mehr auf Schließungen. Die erste ist, dass Funktionssignatur geschlossen werden kann, so dass Sie es nicht neu schreiben müssen.

Zugriff params durch Zahlen

let resultShortAnon = test({return "ANON_" + $0 + "__ANON" })

Params Inferenz mit Benennung

let resultShortAnon2 = test({myParam in return "ANON_" + myParam + "__ANON" })

Rollier Closure

Mit diesem Sonderfall funktioniert nur, wenn der Block das letzte Argument ist, es heißt Hinter Schließung

Hier ist ein Beispiel (mit gefolgerten Unterschrift fusionierte Swift Macht zu zeigen)

let resultTrailingClosure = test { return "TRAILCLOS_" + $0 + "__TRAILCLOS" }

Schließlich:

Mit all dieser Macht, was ich tun würde, ist das Mischen Schließung und Typinferenz Hinter (mit zur besseren Lesbarkeit zu benennen)

PFFacebookUtils.logInWithPermissions(permissions) {
    user, error in
    if (!user) {
        println("Uh oh. The user cancelled the Facebook login.")
    } else if (user.isNew) {
        println("User signed up and logged in through Facebook!")
    } else {
        println("User logged in through Facebook!")
    }
}

Hallo, Swift

Als Ergänzung zu was @Francescu beantwortet.

Hinzufügen zusätzlicher Parameter:

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)

Sie können das Format unten folgen und die testingObjectiveCBlock Eigenschaft in der Klasse verwenden können.

typedef void (^testingObjectiveCBlock)(NSString *errorMsg);

@interface MyClass : NSObject
@property (nonatomic, strong) testingObjectiveCBlock testingObjectiveCBlock;
@end

Für weitere Informationen rel="nofollow"> hier einen Blick

scroll top