Как передать Block
в Function
/Method
?
Я попробовал - (void)someFunc:(__Block)someBlock
безрезультатно.
т. Каков тип Block
?
Как передать Block
в Function
/Method
?
Я попробовал - (void)someFunc:(__Block)someBlock
безрезультатно.
т. Каков тип Block
?
Тип блока изменяется в зависимости от его аргументов и типа возвращаемого значения. В общем случае типы блоков объявляются одинаковыми типами указателей функций, но заменяя *
на ^
. Один способ передать блок методу:
- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
Но, как вы можете видеть, это беспорядочно. Вместо этого вы можете использовать typedef
, чтобы сделать типы блоков более чистыми:
typedef void (^ IteratorBlock)(id, int);
И затем передайте этот блок методу:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
Это может быть полезно:
- (void)someFunc:(void(^)(void))someBlock;
Простейшим объяснением этого вопроса являются следующие шаблоны:
1. Блокировать как параметр метода
Шаблон
- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
// your code
}
Пример
-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
// your code
}
Другое использование случаев:
2. Блокировать как свойство
Шаблон
@property (nonatomic, copy) returnType (^blockName)(parameters);
Пример
@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);
3. Блокировать как аргумент метода
Шаблон
[anObject aMethodWithBlock: ^returnType (parameters) {
// your code
}];
Пример
[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
// your code
}];
4. Блокировать как локальную переменную
Шаблон
returnType (^blockName)(parameters) = ^returnType(parameters) {
// your code
};
Пример
void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
// your code
};
5. Блокировать как typedef
Шаблон
typedef returnType (^typeName)(parameters);
typeName blockName = ^(parameters) {
// your code
}
Пример
typedef void(^completionBlock)(NSArray *array, NSError *error);
completionBlock didComplete = ^(NSArray *array, NSError *error){
// your code
};
Вы можете сделать это, передавая блок как параметр блока:
//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);
Еще один способ передать блок с использованием функций в примере ниже. Я создал функции для выполнения чего-либо в фоновом режиме и в главной очереди.
файл 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);
}
Затем импортируйте blocks.h при необходимости и вызовите его:
- (void)loadInBackground {
performInBackground(^{
NSLog(@"Loading something in background");
//loading code
performOnMainQueue(^{
//completion hadler code on main queue
});
});
}
Вы также можете установить блок как простое свойство, если оно применимо для вас:
@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);
убедитесь, что свойство block является "копией"!
и, конечно, вы также можете использовать typedef:
typedef void (^SimpleBlock)(id);
@property (nonatomic, copy) SimpleBlock someActionHandler;
Также вы вызываете или вызываете блок с использованием обычного синтаксиса функции c
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
Дополнительная информация о блоках здесь
Несмотря на ответы, приведенные в этом потоке, я действительно пытался написать функцию, которая возьмет блок как функцию - и с параметром. В конце концов, вот решение, которое я придумал.
Я хотел написать общую функцию 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! (Не забудьте проголосовать за этот вопрос и мой ответ, если он это сделает!)
Я всегда забываю о синтаксисе блоков. Это всегда приходит мне на ум, когда мне нужно объявить блок. Я надеюсь, что это поможет кому-то:)
Я написал блок завершения для класса, который вернет значения костей после того, как они были потрясены:
Определите typedef с объявлением returnType (.h
выше @interface
)
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
Определите @property
для блока (.h
)
@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
Определите метод с finishBlock
(.h
)
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
Вставить предыдущий определенный метод в файл .m
и зафиксировать finishBlock
до @property
, определенный перед
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
Чтобы запустить completionBlock
передать предопределенный переменный тип ему
(Не забудьте проверить, существует ли completionBlock
)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}