Блок Objective-C в качестве параметра - PullRequest
135 голосов
/ 29 октября 2011

Как я могу передать Block в Function / Method?

Я пытался - (void)someFunc:(__Block)someBlock безрезультатно.

т. Что такое тип для Block?

Ответы [ 11 ]

246 голосов
/ 29 октября 2011

Тип блока зависит от его аргументов и типа возвращаемого значения.В общем случае типы блоков объявляются так же, как и типы указателей на функции, но заменяют * на ^.Один из способов передать блок методу:

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

Но, как вы можете видеть, это грязно.Вместо этого вы можете использовать typedef, чтобы сделать типы блоков более чистыми:

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

, а затем передать этот блок методу, например:

- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
52 голосов
/ 26 августа 2015

Самое простое объяснение этого вопроса - использовать следующие шаблоны:

1. Блок в качестве параметра метода

Template

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

Пример

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

Другие случаи использования:

2. Блок как объект недвижимости

Template

@property (nonatomic, copy) returnType (^blockName)(parameters);
* 1 033 ** +1035 * Пример * +1036 ** * тысячу тридцать-восемь
@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);

3. Блок в качестве аргумента метода

Template

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

* * Пример тысячи пятьдесят-три

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

4. Блок как локальная переменная

Template

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

Пример

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

5. Блок как typedef

Template

typedef returnType (^typeName)(parameters);

typeName blockName = ^(parameters) {
    // your code
}
* 1 087 * Пример * * тысячу девяносто-два
typedef void(^completionBlock)(NSArray *array, NSError *error);

completionBlock didComplete = ^(NSArray *array, NSError *error){
    // your code
};
51 голосов
/ 29 октября 2011

Это может быть полезно:

- (void)someFunc:(void(^)(void))someBlock;
23 голосов
/ 01 ноября 2013

Вы можете сделать это, передав блок в качестве параметра блока:

//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);
8 голосов
/ 14 мая 2014

Еще один способ передать кадр с помощью функции в примере ниже.Я создал функции для выполнения чего-либо в фоновом режиме и в главной очереди.

файл blocks.h

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

файл blocks.m

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

Чем импортировать блоки.h при необходимости и вызвать его:

- (void)loadInBackground {

    performInBackground(^{

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

        performOnMainQueue(^{
            //completion hadler code on main queue
        });
    });
}
6 голосов
/ 18 февраля 2013

Вы также можете установить блок как простое свойство, если оно применимо для вас:

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

убедитесь, что свойство блока является «копировать»!

и, конечно, вы также можете использоватьtypedef:

typedef void (^SimpleBlock)(id);

@property (nonatomic, copy) SimpleBlock someActionHandler;
5 голосов
/ 08 декабря 2012

Также вы вызываете или вызываете блок, используя обычный синтаксис функции c

-(void)iterateWidgets:(IteratorBlock)iteratorBlock{

    iteratorBlock(someId, someInt);
}

Больше информации о блоках здесь

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

3 голосов
/ 11 февраля 2015

Я всегда склонен забывать о синтаксисе блоков.Это всегда приходит мне на ум, когда мне нужно объявить блок.Надеюсь, это кому-нибудь поможет:)

http://fuckingblocksyntax.com

2 голосов
/ 28 января 2015

Я написал завершениеBlock для класса, который будет возвращать значения кубиков после их встряхивания:

  1. Определить typedef с returnType (.h выше @interface декларация)

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
    
  2. Определить @property для блока (.h)

    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
    
  3. Определить метод с помощью finishBlock (.h)

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
    
  4. Вставить предыдущий определенный метод в .m файл и зафиксировать finishBlock в @property, определенный до

    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
    
  5. Чтобы вызвать completionBlock, передайте ему предопределенную переменнуюType (не забудьте проверить, существует ли completionBlock)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }
    
2 голосов
/ 09 декабря 2014

Несмотря на ответы, данные в этой теме, я действительно изо всех сил пытался написать функцию, которая бы принимала блок как функцию - и с параметром. В конце концов, вот решение, которое я придумал.

Я хотел написать обобщенную функцию, loadJSONthread, которая будет принимать URL-адрес веб-службы JSON, загружать некоторые данные JSON из этого URL в фоновый поток, а затем возвращать NSArray * результатов обратно в вызывающую функцию .

По сути, я хотел скрыть всю сложность фонового потока в общей многократно используемой функции.

Вот как бы я назвал эту функцию:

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

} ];

... и это бит, с которым я боролся: как объявить его и как заставить его вызывать функцию Block после загрузки данных и передавать Block NSArray * загруженных записей:

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

        });
    });
}

Этот вопрос StackOverflow касается того, как вызывать функции, передавая блок в качестве параметра, поэтому я упростил приведенный выше код и не включил функцию loadJSONDataFromURL.

Но, если вам интересно, вы можете найти копию этой функции загрузки JSON в этом блоге: http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm

Надеюсь, это поможет другим разработчикам XCode! (Не забудьте проголосовать и ответить на этот вопрос и мой ответ!)

...