如何将a传递Block
给Function
/ Method
?
我- (void)someFunc:(__Block)someBlock
无济于事。
即。是什么类型的Block
?
如何将a传递Block
给Function
/ Method
?
我- (void)someFunc:(__Block)someBlock
无济于事。
即。是什么类型的Block
?
Answers:
块的类型根据其参数和返回类型而有所不同。在一般情况下,块类型中声明的相同方式函数指针类型,但在更换*
带^
。将块传递给方法的一种方法如下:
- (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);
)
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;
您可以这样做,将block作为block参数传递:
//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
});
});
}
您也可以使用通常的c函数语法来调用或调用一个块
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{
iteratorBlock(someId, someInt);
}
有关块的更多信息,请点击此处
我为一个类编写了completeBlock,该类将在摇动后返回骰子的值:
使用returnType定义typedef(.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
传递预定义的variableType到它(别忘了检查是否completionBlock
存在)
if( self.completeDiceRolling ){
self.completeDiceRolling(self.dieValue);
}
尽管在该线程上给出了答案,但我确实很难编写一个将Block作为函数的带参数的函数。最终,这是我想出的解决方案。
我想编写一个通用函数,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函数,并传递已加载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问题涉及如何调用函数,将Block作为参数传递,因此我简化了上面的代码,但没有包括 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 {
}