I have used blocks a few times but never with declaring a typedef first.
I am trying to setup this definitions on a class (lets call it ClassA)
typedef void (^myBlock)();
#property (nonatomic, copy) myBlock onCompletion;
Then I create an instance of the object this class represents and do this:
ClassA *obj = [[ClassA alloc] init];
obj.onCompletion = ^(){
// my code here
};
it is complaining "incompatible block pointer types assigning"...
can you guys explain?
Although you don't have to specify the return type of a block, you must specify void if your block doesn't take any parameters.
Check out this link for block reference: block syntax
Just guessing it might be because you left the block parameter type blank.
typedef void (^myBlock)(void); //Untested
At the request of the OP I am posting my original comment as an answer even though there are other answers stating the same thing:
You need to clearly specify that the block takes no parameters. Your typedef should be:
typedef void (^myBlock)(void);
The only difference in the declared block type myBlock and the type of the block literal might be the return type.
If you leave the return type out in a block literal the compiler figures it out automatically:
myBlock block1 = ^() { // everything is fine
return;
};
myBlock block2 = ^() { // does not work, types differ
return 1;
};
Related
Upon receiving an NSString, I would like to call a specific code block. I figured an NSDictionary would be best for associating these. Simplified, I'm using something like:
MyProtocol.h:
#protocol MyProtocol <NSObject>
typedef void (^Handler)(id<MyProtocol> obj, id data);
#end
MyClass.h:
#interface MyClass : NSObject <MyProtocol>
- (void)aMethodWithString:(NSString *)string andData:(id)data;
#end
MyClass.m:
#interface MyClass ()
void myCommandHandler(id<MyProtocol> obj, id data); // matches signature defined in protocol
#end
#implementation MyClass
void myCommandHandler(id<MyProtocol> obj, id data)
{
// ...
}
- (void)aMethodWithString:(NSString *)string andData:(id)data
{
static NSDictionary<NSString *, Handler> *handler;
static dispatch_once_t onceToken;
// don't allocate this dictionary every time the function is called
dispatch_once(&onceToken,
^{
handler =
#{
#"MyCommand":myCommandHandler,
};
});
// ... error checking, blah blah ...
Handler block;
if ((block = handler[string]))
{ block(self, data); }
}
#end
Using this, I get an error in the dictionary literal construction:
Collection element of type 'void (__strong id<MyProtocol>, __strong id)' is not an Objective-C object`
So how can I include a C function or block reference in the dictionary? There will be quite a few larger complex functions to be defined, so it would be very much preferred to not have all of them defined inside the dictionary literal itself (a technique I know will work).
--
Also, I'm not sure what's considered proper style here: (1) I originally had the dictionary declaration outside of any method body at the file scope (without the dispatch_once(...)) which generates the same error, but I thought maybe it would be easier for others to see what's going on by (2) including it in the only method that uses that dictionary. Is one style preferred over the other for any reason?
Your Handler type is a block type, not a function pointer type. If you had declared it using * instead of ^, it would be a function pointer type.
Your myCommandHandler function is, of course, a function, not a block. Your comment is wrong. It does not match type Handler.
Function pointers are not Objective-C object pointers. Functions are not objects. Blocks are Objective-C objects, but you're not actually using any blocks here. (You've just declared a typedef for one, but you're not actually using it.)
You could use blocks and store them in your dictionary. The blocks could either contain the desired code or call a function or method which does.
A C function address is not an Objective-C object, and an NSDictionary can only store the latter.
A C function address is just a pointer, to wrap a C pointer as an object you use NSValue and its class method valueWithPointer.
To get the pointer value back from the NSValue object you use the instance method pointerValue. Before you can use the extracted pointer you must cast it to your function type.
HTH
I want to call a C function from my ObjC. I am passing a C function reference (defined in ObjC) in a C struct so that C can call that function. I also want to pass the reference to a completion-block to C, so that when I get a callback, I can call that completion-block. But I do not know how to implement that. I get different errors based on the different typecasting I tried.
//Abc.m
void myCallback(MyData *data)
{
//I get the control here!
//((__bridge void *)(data->completionBlock))([NSString stringWithCString:data->json]); //how to call the completion block?
}
- (void)myMethod:(NSString)input
completion:(void (^)(NSString * _Nullable response))completionBlock
{
MyData *data = malloc(sizeof(MyData));
data->myCallback = myCallback;
data->completionBlock = (__bridge void *)(completionBlock);//is this correct?
cFunction(data);
}
//Xyz.c
typedef struct
{
char *json;
void (*myCallback)(void *response);
void *completionBlock;
} MyData;
void cFunction(MyData *data)
{
data->json = "some response";
(data->myCallback)(data);
}
There are two issues to consider:
Casting: You need to cast to appropriate types, e.g. your commented out (__bridge void *)(data->completionBlock) doesn't give you back a block type so the compiler will reject the call.
Ownership: Blocks are just objects in Objective-C and are managed by ARC for you. In C blocks are manually managed. You must ensure that the block you pass into your C structure will not be released by ARC, and having used it you must ensure that it is freed.
Following your code design let's first define a type to make things easier:
typedef void (^CompletionBlock)(NSString * _Nullable response);
With that your myMethod function starts as before:
- (void)myMethod:(NSString*)input
completion:(CompletionBlock)completionBlock
{
MyData *data = malloc(sizeof(MyData));
data->myCallback = myCallback;
Now you must store your block into your struct while making sure ARC does not release it on the Objective-C side. To do that you use __bridge_retain which returns a retained reference to the block, your code will be responsible for balancing that retain. That can either be done in your C code or you can transfer the ownership back to ARC and let it take care of it. So the remainder of myMethod is:
data->completionBlock = (__bridge_retained void *)(completionBlock);
cFunction(data);
}
Now your cFunction just calls your myCallBack function so in this case there is no need to change anything there.
Now to your myCallBack, first we fix the type mismatch and define it to take a void * and then recover the MyData *:
void myCallback(void *response)
{
MyData *data = response;
Now we need to recover the block. We could just cast it to the block type, but that would leave us with the job of freeing it (using Block_release()) after we've used it; however we can use __bridge_transfer to hand back ownership to ARC so it will manage it:
CompletionBlock completionBlock = (__bridge_transfer CompletionBlock)data->completionBlock;
Now we get the string out and convert it to an NSString:
NSString *result = [NSString stringWithCString:data->json encoding:NSUTF8StringEncoding];
And then free the malloc'ed wrapper:
free(data);
Finally we call the block:
completionBlock(result);
}
The above followed your design, but there is no need to have your C function call another C function in your Objective-C file to call the block - blocks are a C language feature and supported in .c files by Clang. You can just cast data->completionBlock to the block type, invoke it, and then use Block_release() to free the block.
Further as blocks are C types you can type the struct field completionBlock with a block type and remove a lot of casts (but those cases cost nothing at runtime).
HTH
__bridge means to use c style pointer, its behaviour like assign or __unsafe_unretained.
You use it mean data->completionBlock just point to completionBlock without retain, so you may crash when completionBlock has been released.
If you wanna access block or objective-c object in struct with ARC, you have to declare these with __unsafe_unretained and manager their life by yourself.
typedef struct {
char *json;
__unsafe_unretained NSString *name;
__unsafe_unretained CompletionBlock block;
} SampleStruct;
Today I want to learn how to use typedef to define a block type. I read the related content from "IOS developer library". But I feel confused about some statement of the sentences.
As an example, you can define a type for a simple block with no arguments or return value, like this:
typedef void (^XYZSimpleBlock)(void);
You can then use your custom type for method parameters or when creating block variables:
XYZSimpleBlock anotherBlock = ^{
...
};
- (void)beginFetchWithCallbackBlock:(XYZSimpleBlock)callbackBlock {
...
callbackBlock();
}
Custom type definitions are particularly useful when dealing with blocks that return blocks or take other blocks as arguments. Consider the following example:
void (^(^complexBlock)(void (^)(void)))(void) = ^ (void (^aBlock)(void)) {
...
return ^{
...
};
};
The complexBlock variable refers to a block that takes another block as an argument (aBlock) and returns yet another block.
Rewriting the code to use a type definition makes this much more readable:
XYZSimpleBlock (^betterBlock)(XYZSimpleBlock) = ^ (XYZSimpleBlock aBlock) {
...
return ^{
...
};
}
The question I want to ask is that how to convert the expression from
void (^(^complexBlock)(void (^)(void)))(void)
to
XYZSimpleBlock (^betterBlock)(XYZSimpleBlock) = ^ (XYZSimpleBlock aBlock)
?
I am new to Objective-C, I was following Apple's "Programming with Objective_C", I can't understand this code sample:
void (^(^complexBlock)(void (^)(void)))(void) = ^ (void (^aBlock)(void)) {
//some code
return ^{
//some code
};
};
I was expecting this pattern:
ReturnType ^(blockVariableIdentifier)(ParameterType1, ParameterType2, ...) = ^{
//some code
};
How was blockVariableIdentifier repleaced with (^complexBlock)(void (^)(void)) ?
isn't it supposed to have void as a return, how come that we have return { ... } ?
I find this code confusing, can you explain it ?
code source.
Update:
Given this typedef:
typedef void (^XYZSimpleBlock)(void);
I can simplify the declaration of complexBlock to:
void (^(^complexBlock)(XYZSimpleBlock))(void);
but I still can't figure out how this is equivalent to
XYZSimpleBlock (^betterBlock)(XYZSimpleBlock);
It is said right there at your link:
The complexBlock variable refers to a block that takes another block as an argument (aBlock) and returns yet another block.
This is just block that returns another block. There is also simplification of that code:
typedef void (^XYZSimpleBlock)(void);
XYZSimpleBlock (^betterBlock)(XYZSimpleBlock) = ^(XYZSimpleBlock aBlock) {
...
return ^{
...
};
};
Return type of betterBlock is XYZSimpleBlock so you return another block from there. void relates only for XYZSimpleBlock, look at its typedef - block that have no arguments and do not return anything
Also this awesome answer will be useful to you
According to this answer (found in #Ahmed Lotfy's comment above) this is just a matter of language/compiler design, but to visuailze how that happened I made this image:
The expected syntax (top) of a block that takes a block as argument and returns a block, that is not accepted by Xcode.
The desgined syntax (bottom).
Visually what happened is just cutting the boxed )(void) and putting it at the end.
we can see it as analogy to a functin returning a block:
void (^f())(void) {
return ^{ ... };
}
just by substituting f() with (^myBlock)(void (^) (void)) which is a block taking another block as a parameter with no return.
I hope we can live with that.
typedef void (^RequestProductsCompletionHandler)(BOOL success, NSArray * products);
I am having difficulty understanding what this line of code is doing in .h file.
Please explain in detail
typedef.
void (I know what void do, but whats the purpose here?).
(^RequestProductsCompletionHandler)(BOOL success, NSArray * products);
How to call it?
This is definition of objective-c block type with name RequestProductsCompletionHandler that takes 2 parameters (BOOL and NSArray) and does not have return value. You can call it the same way you would call c function, e.g.:
RequestProductsCompletionHandler handler = ^(BOOL success, NSArray * products){
if (success){
// Process results
}
else{
// Handle error
}
}
...
handler(YES, array);
Vladimir described it well. It defines a variable type which will represent a block that will pass two parameters, a boolean success and an array of products, but the block itself returns void. While you don't need to use the typedef, it makes the method declaration a tad more elegant (and avoids your having to engage in the complicated syntax of block variables).
To give you a practical example, one might infer from the name of the block type and its parameters that this defines a completion block (e.g. a block of code to be performed when some asynchronous operation, like a slow network request, completes). See Using a Block as a Method Argument.
For example, imagine that you had some InventoryManager class from which you could request product information, with a method with an interface defined like so, using your typedef:
- (void)requestProductsWithName:(NSString *)name completion:(RequestProductsCompletionHandler)completion;
And you might use the method like so:
[inventoryManager requestProductsWithName:name completion:^(BOOL success, NSArray * products) {
// when the request completes asynchronously (likely taking a bit of time), this is
// how we want to handle the response when it eventually comes in.
for (Product *product in products) {
NSLog(#"name = %#; qty = %#", product.name, product.quantity);
}
}];
// but this method carries on here while requestProductsWithName runs asynchronously
And, if you looked at the implementation of requestProductsWithName, it could conceivably look something like:
- (void)requestProductsWithName:(NSString *)name completion:(RequestProductsCompletionHandler)completion
{
// initiate some asynchronous request, e.g.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// now do some time consuming network request to get the products here
// when all done, we'll dispatch this back to the caller
dispatch_async(dispatch_get_main_queue(), {
if (products)
completion(YES, products); // success = YES, and return the array of products
else
completion(NO, nil); // success = NO, but no products to pass back
});
});
}
Clearly, this is unlikely to be precisely what your particular completion handler block is doing, but hopefully it illustrates the concept.
Mike Walker created a nice one page site that shows all possibilities to declare a block in Objective-C. This can be helpful to understand your problem as well:
http://fuckingblocksyntax.com
To quote his site, this is how you can define blocks:
As a local variable:
returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
As a property:
#property (nonatomic, copy) returnType (^blockName)(parameterTypes);
As a method parameter:
- (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName {...}
As an argument to a method call:
[someObject someMethodThatTakesABlock: ^returnType (parameters) {...}];
As a typedef:
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^(parameters) {...}