我尝试使用
- (void)someFunc:(__Block)someBlock
,但无济于事。例如,一个 Block 的类型是什么?
- (void)someFunc:(__Block)someBlock
,但无济于事。块的类型取决于其参数和返回类型。在一般情况下,块类型的声明方式与函数指针类型相同,只是将 *
替换为 ^
。将块传递给方法的一种方式如下:
- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;
但是,正如您所看到的那样,这很混乱。您可以使用 typedef
来使代码块类型更清晰:
typedef void (^ IteratorBlock)(id, int);
然后将该块传递给方法,如下所示:
- (void)iterateWidgets:(IteratorBlock)iteratorBlock;
NSNumber *
或者 std::string&
等任何可以作为函数参数传递的内容。这只是一个例子。(如果要用等效于 id
但替换为 NSNumber
的块,那么 typedef
将是 typedef void (^ IteratorWithNumberBlock)(NSNumber *, int);
) - Jonathan GrynspanNS_NOESCAPE
修饰,但我被告知enumerateObjectsUsingBlock
是非逃逸的,然而我在任何地方都没有看到NS_NOESCAPE
,也没有在Apple文档中提到逃逸。你能帮忙吗? - Mark A. Donohoe最简单的解释是按照以下模板进行操作:
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);
以下是使用C函数传递块的另一种方法。在下面的示例中,我创建了函数来在后台和主队列中执行任何操作。
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);
}
- (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);
请确保块属性为"copy"!
当然,您也可以使用typedef:
typedef void (^SimpleBlock)(id);
@property (nonatomic, copy) SimpleBlock someActionHandler;
你可以使用常规的C函数语法调用块。
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
我为一个类编写了一个completionBlock,在摇晃骰子后返回它们的值:
Define typedef with returnType (.h
above @interface
declaration)
typedef void (^CompleteDiceRolling)(NSInteger diceValue);
Define a @property
for the block (.h
)
@property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
Define a method with finishBlock
(.h
)
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
Insert previous defined method in .m
file and commit finishBlock
to @property
defined before
- (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
self.completeDiceRolling = finishBlock;
}
To trigger completionBlock
pass predefined variableType to it
(Don't forget to check whether the completionBlock
exists)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
loadJSONthread
,该函数将获取 JSON Web 服务的 URL,在后台线程中从该 URL 加载一些 JSON 数据,然后将结果作为 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
并传递一个已加载记录的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);
});
});
}
loadJSONDataFromURL
函数。