wake-up-neo.com

Objective-C-Passblock als Parameter

Wie kann ich eine Block an eine Function/Method übergeben?

Ich habe - (void)someFunc:(__Block)someBlock ohne Erfolg versucht.

dh. Was ist der Typ für eine Block?

133
Jacksonkr

Der Typ eines Blocks hängt von seinen Argumenten und seinem Rückgabetyp ab. Im Allgemeinen werden Blocktypen genauso deklariert wie Funktionszeigertypen, jedoch wird * durch einen ^ ersetzt. Eine Methode zum Übergeben eines Blocks an eine Methode ist wie folgt:

- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;

Aber wie Sie sehen können, ist das chaotisch. Sie können stattdessen eine typedef verwenden, um Blocktypen sauberer zu machen:

typedef void (^ IteratorBlock)(id, int);

Und dann übergeben Sie diesen Block an eine Methode wie folgt:

- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
244

Das könnte hilfreich sein:

- (void)someFunc:(void(^)(void))someBlock;
50
quaertym

Die einfachste Erklärung für diese Frage lautet wie folgt:

1. Block als Methodenparameter

Vorlage

- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
        // your code
}

Beispiel

-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
        // your code
}

Andere Verwendung von Fällen:

2. Als Eigenschaft blockieren

Vorlage

@property (nonatomic, copy) returnType (^blockName)(parameters);

Beispiel

@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);

3. Blockieren als Methodenargument

Vorlage

[anObject aMethodWithBlock: ^returnType (parameters) {
    // your code
}];

Beispiel

[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
    // your code
}];

4. Block als lokale Variable

Vorlage

returnType (^blockName)(parameters) = ^returnType(parameters) {
    // your code
};

Beispiel

void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
    // your code
};

5. Block als typedef

Vorlage

typedef returnType (^typeName)(parameters);

typeName blockName = ^(parameters) {
    // your code
}

Beispiel

typedef void(^completionBlock)(NSArray *array, NSError *error);

completionBlock didComplete = ^(NSArray *array, NSError *error){
    // your code
};
45
EnriMR

Sie können dies so tun, indem Sie einen Block als Blockparameter übergeben:

//creating a block named "completion" that will take no arguments and will return void
void(^completion)() = ^() {
    NSLog(@"bbb");
};

//creating a block namd "block" that will take a block as argument and will return void
void(^block)(void(^completion)()) = ^(void(^completion)()) {
    NSLog(@"aaa");
    completion();
};

//invoking block "block" with block "completion" as argument
block(completion);
22
Aleksei Minaev

Eine weitere Möglichkeit, Block mit с-Funktionen zu übergeben, ist im Beispiel unten angegeben. Ich habe Funktionen erstellt, um im Hintergrund und in der Hauptwarteschlange alles auszuführen.

datei blocks.h

void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));

blocks.m Datei

#import "blocks.h"

void performInBackground(void(^block)(void)) {
    if (nil == block) {
        return;
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}

void performOnMainQueue(void(^block)(void)) {
    if (nil == block) {
        return;
    }

    dispatch_async(dispatch_get_main_queue(), block);
}

Dann importiere blocks.h wenn nötig und rufe es auf:

- (void)loadInBackground {

    performInBackground(^{

        NSLog(@"Loading something in background");
        //loading code

        performOnMainQueue(^{
            //completion hadler code on main queue
        });
    });
}
7
Dren

Sie können block auch als einfache Eigenschaft festlegen, wenn dies für Sie zutrifft:

@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);

stellen Sie sicher, dass die Block-Eigenschaft "copy" ist!

und natürlich können Sie auch typedef verwenden:

typedef void (^SimpleBlock)(id);

@property (nonatomic, copy) SimpleBlock someActionHandler;
6
iiFreeman

Sie rufen auch einen Block mit der üblichen c-Funktionssyntax auf

-(void)iterateWidgets:(IteratorBlock)iteratorBlock{

    iteratorBlock(someId, someInt);
}

Mehr Infos zu den Blöcken hier

http://developer.Apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxGettingStarted.html#//Apple_ref/doc/uid/TP40007502-CH7-SW1

5
gheese

Ich neige immer dazu, die Block-Syntax zu vergessen. Das fällt mir immer ein, wenn ich eine Blockade erklären muss. Ich hoffe es hilft jemandem :)

http://fuckingblocksyntax.com

3
Juan F. Sagasti

Trotz der Antworten in diesem Thread hatte ich wirklich Schwierigkeiten, eine Funktion zu schreiben, die einen Block als Funktion und mit einem Parameter verwenden würde. Schließlich ist hier die Lösung, die ich mir ausgedacht habe.

Ich wollte eine generische Funktion, loadJSONthread, schreiben, die die URL eines JSON-Web-Service übernehmen würde, einige JSON-Daten von dieser URL in einen Hintergrundthread laden und dann ein NSArray * der Ergebnisse an die aufrufende Funktion zurückgeben würde.

Grundsätzlich wollte ich die Hintergrund-Thread-Komplexität in einer generischen, wiederverwendbaren Funktion verborgen halten.

So würde ich diese Funktion nennen:

NSString* WebServiceURL = @"http://www.inorthwind.com/Service1.svc/getAllCustomers";

[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) {

    //  Finished loading the JSON data
    NSLog(@"Loaded %lu rows.", (unsigned long)results.count);

    //  Iterate through our array of Company records, and create/update the records in our SQLite database
    for (NSDictionary *oneCompany in results)
    {
        //  Do something with this Company record (eg store it in our SQLite database)
    }

} ];

... und dies ist das Bit, mit dem ich zu kämpfen hatte: wie man es deklariert und wie man die Block-Funktion aufruft, wenn die Daten geladen wurden, und die Variable Block ein NSArray * der geladenen Datensätze übergeben wird:

+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData
{
    __block NSArray* results = nil;

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{

        // Call an external function to load the JSON data 
        NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString];
        results = [dictionary objectForKey:@"Results"];

        dispatch_async(dispatch_get_main_queue(), ^{

            // This code gets run on the main thread when the JSON has loaded
            onLoadedData(results);

        });
    });
}

Diese StackOverflow-Frage bezieht sich auf das Aufrufen von Funktionen, wobei ein Block als Parameter übergeben wird. Daher wurde der Code oben vereinfacht und die loadJSONDataFromURL-Funktion nicht eingeschlossen. 

Bei Interesse finden Sie jedoch eine Kopie dieser JSON-Ladefunktion in diesem Blog: http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm

Hoffe, das hilft einigen anderen XCode-Entwicklern! (Vergessen Sie nicht, diese Frage und meine Antwort abzustimmen, falls dies der Fall ist!)

2
Mike Gledhill

Ich habe einen CompletionBlock für eine Klasse geschrieben, der die Werte von Würfeln zurückgibt, nachdem sie geschüttelt wurden:

  1. Typedef mit returnType definieren (.h über @interface-Deklaration)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
    
  2. Definieren Sie einen @property für den Block (.h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
    
  3. Definieren Sie eine Methode mit finishBlock (.h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
    
  4. Fügen Sie die zuvor definierte Methode in die .m-Datei ein und übergeben Sie finishBlock an den zuvor definierten @property

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
    
  5. Um completionBlock auszulösen, übergeben Sie einen vordefinierten variablenTyp an ihn .__ (Vergessen Sie nicht zu überprüfen, ob completionBlock vorhanden ist)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }
    
1
Alex Cio

Die vollständige Vorlage sieht so aus

- (void) main {
    [self someMethodWithSuccessBlock:^{[self successMethod];}
                    withFailureBlock:^(NSError * error) {[self failureMethod:error];}];
}

- (void) someMethodWithSuccessBlock:(void (^) (void))successBlock
                   withFailureBlock:(void (^) (NSError*))failureBlock {

    //Execute a block
    successBlock();
//    failureBlock([[NSError alloc]init]);

}

- (void) successMethod {

}

- (void) failureMethod:(NSError*) error {

}
0
yoAlex5