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

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.

Related

Incompatible block pointer types sending 'void (^ _Nullable)(enum MyReturnCode)' to parameter of type 'void (^)(enum MyReturnCode)'

In Objective-C (Xcode 11.3.1), I have two methods receiving a block pointer as their argument:
- (void)showDialog:(void (^ _Nullable)(enum MyReturnCode returnCode))handler;
- (void)openFile:(void (^ _Nullable)(BOOL success))handler;
typedef NS_ENUM(NSUInteger, MyReturnCode)
{
MyReturnCodeFirstOption,
MyReturnCodeSecondOption
};
The methods are called as follows:
[self showDialog:^(enum MyReturnCode returnCode) {}];
[self openFile:^(BOOL success) {}];
If I try to compile it I get an error on the line calling showDialog:
Incompatible block pointer types sending 'void (^ _Nullable)(enum MyReturnCode)'
to parameter of type 'void (^)(enum MyReturnCode)'
If I try to remove the _Nullable from the method definition, I get an error where both parts as equal:
Incompatible block pointer types sending 'void (^)(enum MyReturnCode)'
to parameter of type 'void (^)(enum MyReturnCode)'
Calls to the openFile method are compiled without any issues.
Why I'm getting the error on the showDialog call?
Why not on openFile where the only difference is the handler return type?
How to fix that?

Using Obj-C completion block in Swift

In Objective-C, I have a completion block class defined as:
File.h
typedef void (^MYCompletionBlock)(BOOL success, NSDictionary *result, NSError *error);
Then, in a Swift file, I try to use the completion block as follows:
Swift.swift
class MyClass: NSObject{
...
func MyFunction() -> Void {
...
objcMethod(param1, withCompletion: {(MYCompletionBlock) -> Void in
if (success){ // Error:"Use of unresolved identifier 'success'"
}
}
...
}
...
}
But, I keep getting an error: "Use of unresolved identifier 'success'".
I've tried the following as well:
objcMethod(param1, withCompletion: {(success:Bool, result: NSDictionary, error:NSError) -> Void in
if (success){ // Error:"Cannot convert value of type '(Bool, NSDictionary, NSError) -> Void' to expected argument type "MYCompletionBlock!"
}
}
Can somebody help me understand how to correctly specify a Obj-C completion block in Swift?
Given that your closure doesn't specify nullability qualifiers (where they almost certainly are optional), one can safely assume that your Objective-C API has not been audited for nullability. Thus, Swift will treat pointers as implicitly unwrapped optionals. Furthermore, nowadays the NSDictionary is mapped to a [NSObject : AnyObject] Swift dictionary.
Thus, it would be:
obj.objcMethod(param) { (success: Bool, result: [NSObject : AnyObject]!, error: NSError!) in
if success {
// do something
}
}
Or, as Kobi points out, you can let the compiler infer the types:
obj.objcMethod(param) { success, result, error in
if success {
// do something
}
}
Note, you don't have to remember this yourself. You can leverage Xcode's code completion as you enter the code. So, type enough to match the method name and when it matches objcMethod, then hit enter:
When you get to MYCompletionBlock, hit enter again, and it will show you the correct signature:
If this Objective-C method was my own class, I would audit it for nullability. So, for example, let's assume the param is optional, the closure is required, and the result and error were optional, you might define it like so:
NS_ASSUME_NONNULL_BEGIN
typedef void (^MYCompletionBlock)(BOOL success, NSDictionary * _Nullable result, NSError * _Nullable error);
#interface MyObject : NSObject
- (void)objcMethod:(NSDictionary * _Nullable)param1 withCompletionHandler:(MYCompletionBlock)completionHandler;
#end
NS_ASSUME_NONNULL_END
And, if that was the case, your Swift code would call it like so:
obj.objcMethod(param) { (success: Bool, result: [NSObject : AnyObject]?, error: NSError?) in
if success {
// do something
}
}
Or, again, just let the compiler infer the types for you (but this time they'd be inferred as optionals that are not implicitly unwrapped):
obj.objcMethod(param) { success, result, error in
if success {
// do something
}
}
You shouldn't specify types for the completion block parameters, as some types defer between Swift and Objective C (e.g. BOOL is actually ObjCBool in Swift).
This should work:
objcMethod(param1) { (success, result, error) in
if (success){
// Do something
}
}

How to call dispatch_block_t directly?

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.

What am I doing wrong with this method definition and call?

I have this in my class header:
typedef void(^DBSuccessBlock)();
typedef void(^DBErrorBlock)(int errorNumber, NSString* description);
- (void) connect:(NSString*) path isFile:(BOOL) flag
success:(DBSuccessBlock) success
error:(DBErrorBlock) error;
This is how I'm trying to call the method:
[db connect:filePathName isFile:YES success:^{
// initialize db here if necessary
} error:^(int errorNumber, NSString *description) { //error on this line
NSLog(description);
return nil;
}];
The error line is giving me this compile error: Incompatible block pointer types sending 'void *(^)(int, NSString *_strong)' to parameter of type 'DBErrorBlock' (aka 'void (^)(int, NSString *_strong)')
The only difference I see is void* vs void and I'm not sure why. Can anyone help me figure out why I'm getting this error? Thanks.
You are returning the value nil in a block with return type void. Remove the return nil line.

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);