What am I doing wrong with this method definition and call? - objective-c-blocks

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.

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.

Incompatible block pointer type? Cannot return NSArray

I have a block we return an array in callback. Then I create another method to store that array as below:
- (NSArray *)getUserData{
[self fetchDataByUserId:self.userID completionHandler:^(NSArray *record) {
return record;
}];
}
I received this kind of error so please help me, I don't understand.
"Incompatible block pointer types sending 'NSArray *(^)(NSArray * __strong) to parameter of type 'void (^)(NSArray *_strong)"
Reason is explained by #user3386109, this is the right way.
- (void)getUserData:(void (^)(NSArray *record))complete {
[self fetchDataByUserId:self.userID completionHandler:^(NSArray *record) {
complete(record);
}];
}
or
- (void)getUserData:(void (^)(NSArray *record))complete {
[self fetchDataByUserId:self.userID completionHandler:complete];
}
Moreover, about the Error Message: "Incompatible block pointer type", you should google "How to use Block in objective-c", ex: http://rypress.com/tutorials/objective-c/blocks
Because your completionHanler is not a return type block, it's a void block.
(void (^)(NSArray *record))
is different with
(NSArray * (^)(NSArray *record))
The completionHandler is not called immediately, and is not expected to return a value. You can think of the code in the completionHandler as a callback function. The caller is some framework code that executes whenever the fetch completes. The framework code calls your completionHandler to let you know that the fetch is finished, and doesn't expect any return value.
So the getUserData method should really be a startUserDataFetch method, and you need additional code to process the data if ever / whenever it actually arrives.

NSError initialization macro stopped working with recent Clang

I am used to using this macro to initialize NSError** arguments:
#define INIT_ERROR_IF_NULL(error) error = error ? error : &(NSError*){ nil }
This checks the passed NSError** argument and if it’s NULL, initializes it to a dummy NSError so that I don’t have to wrap every *error dereference in a conditional. In code, this version:
- (void) doFoo: (NSError**) error
{
if (error) {
*error = [NSError …];
}
}
…turns into this:
- (void) doFoo: (NSError**) error
{
INIT_ERROR_IF_NULL(error);
*error = [NSError …];
}
I like the approach, it saves branching and makes me write less code (of course I don’t bother when the error is being used just once). The problem is that it stopped working in the recent Clang version, as the compiler complains about pointer type mismatch:
Pointer type mismatch ('NSError *__autoreleasing *' and 'NSError **')
If I change the macro to explicitly cast the resulting anonymous object to NSError *__autoreleasing* (the type signatures are getting ridiculous), the compiler complains further, on a different line:
Casting 'NSError **' to type 'NSError *__autoreleasing *' changes retain/release properties of pointer
Again, the variable in question is a method argument. I don’t understand the issue. What can I do to keep my macro?
This compiles without errors/warnings:
#define INIT_ERROR_IF_NULL(error) error = error ? error : &( NSError __autoreleasing *){ nil }

Why can't the address of an ivar be passed to an "id __autoreleasing *" argument under ARC?

Under ARC, an out-parameter takes the following form (by default; this is equivalent to NSError **):
- (BOOL)tryWithError:(NSError *__autoreleasing *)err;
From the Transitioning to ARC Release Notes, if we pass the address of a __strong local variable, the compiler will create a temporary variable and generate the following code:
NSError *error; // strong
BOOL ok = [myObject tryWithError:&error];
// translated to
NSError *__strong error;
NSError *__autoreleasing tmp = error;
BOOL ok = [myObject tryWithError:&tmp];
error = tmp;
But if we do it with an instance variable:
#implementation Foo {
NSError *_error; // strong
}
- (void)bar
{
[myObject tryWithError:&_error];
}
...
this gives us the error
Passing address of non-local object to __autoreleasing parameter for write-back.
Why is this invalid? Couldn't the compiler just translate such code automatically to this?
- (void)bar
{
NSError *__autoreleasing tmp = _error;
[myObject tryWithError:&tmp];
_error = tmp;
}
After all, this is what I will be writing anyway to solve the problem!
Note: adding the out keyword to the parameter type will reduce the compiler's work slightly because it doesn't have to read the current value into the temporary variable — but this doesn't take care of the error.
A pointer to an ivar can't be passed to an “id __autoreleasing *” argument under ARC because that kind of pass-by-writeback is ill-formed. The respective section in the ARC specification lists legal forms of pass-by-writeback, the only one applicable here is
&var, where var is a scalar variable of automatic storage duration
with retainable object
, so only automatic storage duration (a local variable) is allowed.
Why this is invalid: I am pretty sure the reason here is compatibility with older code:
1) You should only look at the error writeback in the failure case. In the success case, there is no guarantee at all what's inside the error pointer.
2) In general, whether the writeback value should be used or not depends on the contract of the method. That is something the compiler cannot check.
This is the version of the code that matches the type of &error (NSError * __autoreleasing *) to the type of the writeback (NSError ** which is interpreted as NSError * __autoreleasing *). If ok is YES, the error value won't be touched.
NSError * __autoreleasing error;
BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {
// use error
}
However, those __autoreleasing are ugly, so instead of forcing us to use __autoreleasing all over the place, the compiler allows us to pass a __strong (but local) variable as well (default ownership):
NSError *error;
BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {
// use error
}
According to the docs, that gets rewritten to:
NSError * __strong error;
NSError * __autoreleasing tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
if (!OK) {
// use error
}
Not a problem at all, the error will only be used in the success case.
Now let's have a look at a __strong instance variable _error. Why doesn't the compiler allow that? Here is what the rewrite would look like:
NSError * __autoreleasing tmp = _error;
BOOL OK = [myObject performOperationWithError:&tmp];
_error = tmp;
if (!OK) {
// use error
}
The problem here is that the writeback in tmp would always be used (assigned to the instance variable _error), ignoring the contract of the method that the writeback should only be used in error cases (or in general whatever the documentation of the method says). A safe way to assign the last error to an instance variable would be
NSError * __autoreleasing tmp = _error;
BOOL OK = [myObject performOperationWithError:&tmp];
if (!OK) {
_error = tmp;
// use error
} else {
_error = nil; // Make sure that _error is nil if there was no error.
}
And that's only true for the convention of Cocoa's methods which return an error. In general there is no way for the compiler to tell what a method will do with an id *: There may be old methods out there that use different conventions. So if you really want to store the writeback in a __strong instance variable, you currently have to walk the extra mile yourself, and I don't expect this to change.

Objective-C Block Syntax

Obj-C blocks are something I'm just using for the first time recently. I'm trying to understand the following block syntax:
In the header file:
#property (nonatomic, copy) void (^completionBlock)(id obj, NSError *err);
In the main file:
-(void)something{
id rootObject = nil;
// do something so rootObject is hopefully not nil
if([self completionBlock])
[self completionBlock](rootObject, nil); // What is this syntax referred to as?
}
I appreciate the assistance!
Blocks are Objects.
In your case inside the method you are checking if the block is not nil and then you are calling it passing the two required arguments ...
Keep in mind that blocks are called in the same way a c function is ...
Below i have split the statement in two to let you understand better :
[self completionBlock] //The property getter is called to retrieve the block object
(rootObject, nil); //The two required arguments are passed to the block object calling it
Its a block property, you can set a block at runtime.
Here is the syntax to set
As it is void type, so within the class you can set a method by following code
self.completionBlock = ^(id aID, NSError *err){
//do something here using id aID and NSError err
};
With following code you can call the method/block set previously.
if([self completionBlock])//only a check to see if you have set it or not
{
[self completionBlock](aID, nil);//calling
}