Domanda

E 'possibile avere blocchi proprietà utilizzando la sintassi proprietà standard?

Ci sono dei cambiamenti per ARC

È stato utile?

Soluzione

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

Se avete intenzione di essere a ripetere lo stesso blocco in più punti usano un tipo def

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

Altri suggerimenti

Ecco un esempio di come si dovrebbe svolgere tale compito una:

#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;
}

Ora, l'unica cosa che avrebbe bisogno di cambiamento se è necessario cambiare il tipo di confronto sarebbe la typedef int (^IntBlock)(). Se è necessario passare due oggetti ad esso, modificarlo a questo: typedef int (^IntBlock)(id, id), e cambiare il tuo blocco:

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

Spero che questo aiuta.

EDIT 12 marzo 2012:

Per ARC, ci sono cambiamenti richiesta nessuna specifica, come ARC gestirà i blocchi per voi fino a quando essi sono definiti come copia. Non è necessario impostare la proprietà a zero nel distruttore, sia.

Per ulteriori lettura, si prega di consultare questo documento: http://clang.llvm.org/docs/AutomaticReferenceCounting.html

Per Swift, basta usare le chiusure: esempio

.

In Objective-C,

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

E 'così semplice.

la documentazione di Apple, che spiega completamente questo problema:

di Apple doco.

Nel file .h:

// 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".

Ecco il file .m:

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

Attenzione di out-of-date codice di esempio.

Con (2014+) sistemi moderni, fare ciò che è qui mostrato. E 'così semplice. Speranza che aiuta qualcuno. Buon Natale 2013!

Per l'amor posteri / di completezza ... Ecco due esempi completi di come implementare questa ridicolmente versatile "modo di fare le cose". @ Risposta di Robert è beatamente concisa e corretta, ma qui voglio mostrare anche modi per effettivamente "definire" i blocchi.

@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

sciocco? Sì. Utile? Hells sì. Ecco un altro modo "altro atomica" dell'impostazione della proprietà .. e una classe che è ridicolmente utile ...

@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

Questo illustra l'impostazione della proprietà del blocco tramite la funzione di accesso (anche se init all'interno, una pratica rischiosa debatably ..) vs il meccanismo del primo esempio "nonatomic" "getter". In entrambi i casi ... le implementazioni "hardcoded" possono sempre essere sovrascritti, per esempio .. A LA ..

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

Inoltre .. se si desidera aggiungere una proprietà di blocco in una categoria ... dire che si desidera utilizzare un blocco al posto di qualche bersaglio vecchia scuola / azione "azione" ... Si può semplicemente utilizzare valori associati a, bene .. associare i blocchi.

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

Ora, quando si effettua un pulsante, non devi impostare qualche dramma IBAction .. Basta associare il lavoro da fare al momento della creazione ...

_button.actionBlock = ^(NSControl*thisButton){ 

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

Questo modello può essere applicato più e più volte cacao API. Utilizzare le proprietà di portare le parti pertinenti del codice più vicini , eliminare paradigmi delegazione contorti , e sfruttare la potenza degli oggetti oltre che di proprio in qualità di "contenitori" muti.

Naturalmente è possibile utilizzare i blocchi come proprietà. Ma fare in modo che siano dichiarati come @property (copia) . Ad esempio:

typedef void(^TestBlock)(void);

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

In MRC, blocchi cattura variabili di contesto sono assegnati in pila ; saranno rilasciati quando il telaio pila viene distrutta. Se sono copiati, un nuovo blocco verrà assegnato nel mucchio , che può essere eseguito successivamente dopo stack frame viene poped.

Disclamer

Questa non è destinato ad essere "la buona risposta", come questa domanda esplicitamente richiesto ObjectiveC. Come Apple ha introdotto Swift al WWDC14, mi piacerebbe condividere i diversi modi per bloccare l'uso (o chiusure) a Swift.

Ciao, Swift

Hai molti modi offerti per passare un blocco equivalente alla funzione a Swift.

Ho trovato tre.

Per capire questo vi suggerisco di testare nel parco giochi questo piccolo pezzo di codice.

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, ottimizzato per le chiusure

Come Swift è ottimizzato per lo sviluppo asincrono, Apple ha lavorato di più sulle chiusure. La prima è che la firma funzione può essere dedotta in modo da non dover riscrivere.

Accesso params da numeri

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

Parametri inferenza con la denominazione

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

Trailing Chiusura

Questo caso particolare funziona solo se il blocco è l'ultimo argomento, si chiama finale di chiusura

Ecco un esempio (si è fusa con la firma dedotto per mostrare il potere Swift)

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

Infine:

Usando tutta questa potenza cosa farei è la miscelazione finale di chiusura e inferenza di tipo (con denominazione per migliorare la leggibilità)

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!")
    }
}

Ciao, Swift

A complemento di ciò che ha risposto @Francescu.

L'aggiunta di parametri extra:

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)

È possibile seguire il modello che segue e può utilizzare la proprietà testingObjectiveCBlock nella classe.

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

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

Per maggiori informazioni date un'occhiata qui

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top