How to call dispatch_block_t directly? - objective-c

I am trying to update some code for XCode 6.1 / Yosemite. It's a bit weird because it's a macro, but essentially it looks like:
dispatch_block_t blk = ^{ [[self globalEventsHandler] someMethod self]; };
if([NSThread isMainThread]) blk();
else dispatch_async(dispatch_get_main_queue(), blk);
This is causing compilation problems. I have already set OS_OBJECT_USE_OBJC=0 per GCD guide in my preprocessor settings, since right now I'm not interested in modernizing the code.
The first is Implicit conversion of block pointer type 'void (^)(void)' to C pointer type 'dispatch_block_t' (aka 'void *') requires a bridged cast. I can accept the suggest fix for this and get:
dispatch_block_t blk = (__bridge dispatch_block_t)^{ [[self globalEventsHandler] someMethod self]; };
if([NSThread isMainThread]) blk();
else dispatch_async(dispatch_get_main_queue(), blk);
but now I get a new error: Called object type 'dispatch_block_t' (aka 'void *') is not a function or function pointer. And on that I'm stuck.
Questions:
Is there a way to call dispatch_block_t directly now? I have found the original code pattern in a few older blog posts, so I suspect it is (was) common.
Is __bridge the correct way to do this? There seem to be other options related to dispatch_retain and friends that may be appropriate.
I feel like I'm missing a fundamental concept here, which would be very likely since I'm quite inexperienced with OSX development.
For bonus points: how would you get this working without disabling OS_OBJECT_USE_OBJC?

That code snippet is totally ok with Xcode 6.1 with OS X SDK 10.10. However, these compile error messages are odd.
Implicit conversion of block pointer type 'void (^)(void)' to C pointer type 'dispatch_block_t' (aka 'void *') requires a bridged cast
Called object type 'dispatch_block_t' (aka 'void *') is not a function or function pointer.
dispatch_block_t should be the following in dispatch/object.h.
typedef void (^dispatch_block_t)(void);
But these error messages say dispatch_block_t is the same as void *. Did you typedef dispatch_block_t yourself instead of including Foundation/Foundation.h or dispatch/dispatch.h? You'd better search dispatch_block_t typedef in your code.

Related

Incompatible block pointer types sending 'void (^__strong)(__strong id)' to parameter of type 'swizzleBlock' (aka 'void (^)(void)')

Trying to fix issues with FBSDKEventBindingManager.m error for few days but still having hard time to find solution.
Error:
Incompatible block pointer types sending 'void (^__strong)(__strong id)' to parameter of type 'swizzleBlock' (aka 'void (^)(void)')
Error in this line => withBlock:blockToSuperview named:#"map_control"];
void (^blockToSuperview)(id view) = ^(id view) {
[self matchView:view delegate:nil];
};
void (^blockToWindow)(id view) = ^(id view) {
[self matchView:view delegate:nil];
};
[FBSDKSwizzler swizzleSelector:#selector(didMoveToSuperview)
onClass:[UIControl class]
withBlock:blockToSuperview named:#"map_control"];
[FBSDKSwizzler swizzleSelector:#selector(didMoveToWindow)
onClass:[UIControl class]
withBlock:blockToWindow named:#"map_control"];
The problem is where FBSDK using typedef for swizzleBlock
typedef void (^swizzleBlock)();
This can be explained like
typedef void (^swizzleBlock)(void); //void (^)(void) format
Line 24 here:
And the parameter being passed is of type
void (^blockToSuperview)(id view) = ^(id view) // void (^__strong)(__strong id)'
Which leads to type mismatch and showing you error
Incompatible block pointer types sending 'void (^__strong)(__strong id)' to parameter of type 'swizzleBlock' (aka 'void (^)(void)')
Refer this, it will helps you to understand the Objective-C block syntax at various points.
You should update the typedef to match the passing block.
typedef void (^swizzleBlock)(id);
Fixing, this will fix the error at a point, but in the same file there are many other types of block with different format, e.g tableViewBlock(line 185), collectionViewBlock(line 200) checkout here. so, you will have to look for some generic workaround to fix it.
Hope it helps.

Running a nil block in Objective C [duplicate]

I started using blocks a lot and soon noticed that nil blocks cause bus errors:
typedef void (^SimpleBlock)(void);
SimpleBlock aBlock = nil;
aBlock(); // bus error
This seems to go against the usual behaviour of Objective-C that ignores messages to nil objects:
NSArray *foo = nil;
NSLog(#"%i", [foo count]); // runs fine
Therefore I have to resort to the usual nil check before I use a block:
if (aBlock != nil)
aBlock();
Or use dummy blocks:
aBlock = ^{};
aBlock(); // runs fine
Is there another option? Is there a reason why nil blocks couldn’t be simply a nop?
I'd like to explain this a bit more, with a more complete answer. First let's consider this code:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
void (^block)() = nil;
block();
}
If you run this then you'll see a crash on the block() line that looks something like this (when run on a 32-bit architecture - that's important):
EXC_BAD_ACCESS (code=2, address=0xc)
So, why is that? Well, the 0xc is the most important bit. The crash means that the processor has tried to read the information at memory address 0xc. This is almost definitely an entirely incorrect thing to do. It's unlikely there's anything there. But why did it try to read this memory location? Well, it's due to the way in which a block is actually constructed under the hood.
When a block is defined, the compiler actually creates a structure on the stack, of this form:
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
The block is then a pointer to this structure. The fourth member, invoke, of this structure is the interesting one. It is a function pointer, pointing to the code where the block's implementation is held. So the processor tries to jump to that code when a block is invoked. Notice that if you count the number of bytes in the structure before the invoke member, you'll find that there are 12 in decimal, or C in hexadecimal.
So when a block is invoked, the processor takes the address of the block, adds 12 and tries to load the value held at that memory address. It then tries to jump to that address. But if the block is nil then it'll try to read the address 0xc. This is a duff address, clearly, and so we get the segmentation fault.
Now the reason it must be a crash like this rather than silently failing like an Objective-C message call does is really a design choice. Since the compiler is doing the work of deciding how to invoke the block, it would have to inject nil checking code everywhere a block is invoked. This would increase code size and lead to bad performance. Another option would be to use a trampoline which does the nil checking. However this would also incur performance penalty. Objective-C messages already go through a trampoline since they need to look up the method that will actually be invoked. The runtime allows for lazy injection of methods and changing of method implementations, so it's already going through a trampoline anyway. The extra penalty of doing the nil checking is not significant in this case.
For more information, see my blog posts.
Matt Galloway's answer is perfect! Great read!
I just want to add that there are some ways to make life easier. You could define a macro like this:
#define BLOCK_SAFE_RUN(block, ...) block ? block(__VA_ARGS__) : nil
It can take 0 – n arguments. Example of usage
typedef void (^SimpleBlock)(void);
SimpleBlock simpleNilBlock = nil;
SimpleBlock simpleLogBlock = ^{ NSLog(#"working"); };
BLOCK_SAFE_RUN(simpleNilBlock);
BLOCK_SAFE_RUN(simpleLogBlock);
typedef void (^BlockWithArguments)(BOOL arg1, NSString *arg2);
BlockWithArguments argumentsNilBlock = nil;
BlockWithArguments argumentsLogBlock = ^(BOOL arg1, NSString *arg2) { NSLog(#"%#", arg2); };
BLOCK_SAFE_RUN(argumentsNilBlock, YES, #"ok");
BLOCK_SAFE_RUN(argumentsLogBlock, YES, #"ok");
If you want to get the return value of the block and you are not sure if the block exists or not then you are probably better off just typing:
block ? block() : nil;
This way you can easily define the fallback value. In my example 'nil'.
Caveat: I'm no expert in Blocks.
Blocks are objective-c objects but calling a block is not a message, although you could still try [block retain]ing a nil block or other messages.
Hopefully, that (and the links) helps.
This is my simple nicest solution… Maybe there is possible to write one universal run function with those c var-args but I don’t know how to write that.
void run(void (^block)()) {
if (block)block();
}
void runWith(void (^block)(id), id value) {
if (block)block(value);
}

Sending 'CGPoint" to parameter of incompatible type in CCCallFuncND

The error in Xcode reads: sending CGPoint (aka 'struct CGPoint') to parameter of incompatible type 'void *'
What I'm doing is:
CCSprite* coordinate= path[i];
CGPoint posSending = coordinate.position;
id handleTail = [CCCallFuncND actionWithTarget:self selector:#selector(handleTail:)data:posSending];
//handleTail
-(void)handleTail:(CGPoint)pos{
}
What's causing this error?
CCCallFuncND doesn't work with struct types (nor does it work well with ARC).
Use the block version instead, much easier, a lot more powerful:
CGPoint posSending = coordinate.position;
id handleTail = [CCCallBlock actionWithTarget:self block:^{
// do something with posSending:
someNode.position = posSending;
}];
FYI the error is because you try to assign a CGPoint type to a void* type. Even if you did use the address of the CGPoint by passing it with the address operator (&posSending) you would receive garbage in your handleTail method. By the time that method is called, the pointer to posSending is no longer valid since posSending was created on the stack.
One might think that malloc'ing the CGPoint would work, and it does - however it's not safe to use because there is no guarantee that the handleTail method is ever going to be called (due to scene changes, or stopAction calls). Therefore it's not guaranteed that the receiving method can actually free that malloc'ed pointer.
In addition, your handleTail method is declared incorrectly, it receives a void* parameter:
-(void)handleTail:(void*)data
{
}
All of this, one takeway: use blocks whenever and whereever you can.

Incompatible block pointer types using typedef

For a day now I've been trying to get a piece of code working to help me handle find-and-create for CoreData in a nice way (from this article I found http://emplementation.blogspot.nl/2011/12/importing-data-into-core-data-while.html). I ended up working with code blocks which I've never done before.
Somehow I can't fix the following error which occurs because something is different in my typedef from what I try to define in my function. I think I understand it has something to do with the block being defined as __strong in the typedef but differently in my implementation file.
Error
Incompatible block pointer types initializing '_strong objectOperationBlock' (aka 'void (^_strong)(NSManagedObjectContext *_strong, NSDictionary *_strong, NSManagedObject *_strong)') with an expression of type 'void (^)(NSManagedObject *_strong, NSDictionary *_strong, NSManagedObject *_strong)'
MyViewController.h
typedef void (^objectOperationBlock)(NSManagedObjectContext *context,
NSDictionary *hostObjectData,
NSManagedObject *localManagedObject);
MyViewController.m
objectOperationBlock matchedBlock = ^(NSManagedObject *context, NSDictionary *hostObjectData, NSManagedObject *localManagedObject){
NSLog(#"Dosomething");
};
In all my attempts I've found out that this could will build (but it's not using the typedef)
void (^matchedBlock)(NSManagedObject*, NSDictionary*, NSManagedObject*) = ^(NSManagedObject *context, NSDictionary *hostObjectData, NSManagedObject *localManagedObject){
NSLog(#"Dosomething");
};
Thanks in advance for all your help!
Did I miss that the typedef should read:
typedef void (^objectOperationBlock)(NSManagedObject *managedObject,
NSDictionary *hostObjectData,
NSManagedObject *localManagedObject);

refactor to ARC gives error implicit error [picture]

I am refactoring to use ARC in my project and can not figure out this problem for the life of me!
I don't know where I got the code from.
screenshot of error http://img341.imageshack.us/img341/972/xcode.png"screenshot of error"
http://img341.imageshack.us/img341/972/xcode.png
The problem is that you are not using bridged casting. You have to use bridging to cast between C types and Objective-C types:
[UIView beginAnimations:#"earthquake" context:(__bridge void *)itemView];
When casting from a C pointer type to an Objective-C type:
UIView * item = (__bridge UIView *)context;