Как я могу передать Block
a Function
/ Method
?
Я безуспешно пытался - (void)someFunc:(__Block)someBlock
.
т.е. Что такое тип для Block
?
objective-c
objective-c-blocks
Джексонкр
источник
источник
Ответы:
Тип блока зависит от его аргументов и типа возвращаемого значения. В общем случае, типы блоков объявляются так же , как типы указателей функции являются, но заменяя
*
с^
. Один из способов передать блок в метод следующий:- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
Но, как видите, это грязно. Вместо этого вы можете использовать a,
typedef
чтобы сделать типы блоков более чистыми:typedef void (^ IteratorBlock)(id, int);
А затем передайте этот блок такому методу:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
источник
NSNumber *
илиstd::string&
или что-нибудь еще, что вы можете передать в качестве аргумента функции. Это всего лишь пример. (Для блока, который эквивалентен, за исключением заменыid
наNSNumber
,typedef
будетtypedef void (^ IteratorWithNumberBlock)(NSNumber *, int);
.)NS_NOESCAPE
, ноenumerateObjectsUsingBlock
мне сказали, что экранирование не выполняется, но яNS_NOESCAPE
нигде не вижу на сайте и не упоминается об экранировании вообще в документации Apple. Вы можете помочь?Самое простое объяснение этого вопроса - следовать этим шаблонам:
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 };
источник
Это может быть полезно:
- (void)someFunc:(void(^)(void))someBlock;
источник
Вы можете сделать это, передав блок в качестве параметра блока:
//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); }
Затем импортируйте блоки .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);
убедитесь, что свойство блока - «копировать»!
и, конечно, вы также можете использовать typedef:
typedef void (^SimpleBlock)(id); @property (nonatomic, copy) SimpleBlock someActionHandler;
источник
Также вы вызываете или вызываете блок, используя обычный синтаксис функции 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.
источник
Я всегда забываю о синтаксисе блоков. Это всегда приходит мне в голову, когда мне нужно объявить блокировку. Надеюсь, это кому-то поможет :)
http://fuckingblocksyntax.com
источник
Я написал блок завершения для класса, который будет возвращать значения кубиков после их встряхивания:
Определите typedef с помощью returnType ( объявление
.h
выше@interface
)typedef void (^CompleteDiceRolling)(NSInteger diceValue);
Определите a
@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); }
источник
Несмотря на ответы, данные в этом потоке, я действительно изо всех сил пытался написать функцию, которая принимала бы блок как функцию - и с параметром. В конце концов, вот решение, которое я придумал.
Я хотел написать общую функцию,
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! (Не забудьте проголосовать за этот вопрос и за мой ответ, если да!)
источник
Полный шаблон выглядит так
- (void) main { //Call [self someMethodWithSuccessBlock:^{[self successMethod];} withFailureBlock:^(NSError * error) {[self failureMethod:error];}]; } //Definition - (void) someMethodWithSuccessBlock:(void (^) (void))successBlock withFailureBlock:(void (^) (NSError*))failureBlock { //Execute a block successBlock(); // failureBlock([[NSError alloc]init]); } - (void) successMethod { } - (void) failureMethod:(NSError*) error { }
источник