在此代码中
id (^block)(void) = ^(void) {
return nil;
};
我有这个错误
不兼容的块指针类型使用类型为'void *(^)(void)'的表达式初始化'id(^ __ strong)(void)'
所以我必须明确地将nil
转换为id
类型
id (^block)(void) = ^(void) {
return (id)nil;
};
让编译器开心。购买nil
不是id
类型的原因?
并为此代码
__typeof__(nil) dummy;
dummy = [NSObject new];
将Objective-C指针类型'NSObject *'隐式转换为C指针类型'typeof(((void *)0))'(又名'void *')需要桥接转换
说nil
是(void *)0
,但与NULL
不一样?我虽然nil
应该是(id)0
而Nil
应该是(Class)0
?
我正在使用Xcode 4.6.2
编译器:Apple LLVM版本4.2(clang-425.0.28)(基于LLVM 3.2svn)
答案 0 :(得分:3)
当一个块省略了它的返回类型时,它现在成为编译器的工作,根据其体内的返回值推断块的类型。但是,不幸的是,CLANG搜索了返回类型的完全腐朽形式,这导致了奇怪的不一致。
最易于访问的示例是对数组进行排序。比较器块的类型是NSComparisonResult(^)(id obj, id obj2)
,但如果您选择省略NSComparisonResult返回类型,则编译器会发出嘶哑的声音:
NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj, id obj2) {
if (//...) return NSOrderedAscending;
return NSOrderedDescending;
}];
此块衰减为类型为int(^)(id obj, id obj2)
的块,编译器认为该块不兼容(可以说,枚举只是命名为int,所以这应该编译)。
以同样的方式,id衰减到objc_object*
,它会一直衰减,直到它到达void*
或“任何通用指针”(根据C语言规范)。 void *和id肯定是不是相同的类型。为了解决这个问题,你必须向编译器保证返回的类型确实就是这样,并且唯一的方法就是强制转换。
LLVM 5.0通过使编译器的推理更加智能化来解决这个问题。
答案 1 :(得分:3)
您正在为块文字使用推断的返回类型,但您没有。
删除该错误的正确方法是为块文字提供返回类型:
id (^block)(void) = ^id{
return nil;
};
答案 2 :(得分:0)
我不知道为什么nil在Apple标题中是#define nil NULL
(这是事实,但我不知道为什么它不像人们期望的那样(id)0
),但我从来没有您在最新版本的Xcode和编译器中提到的错误。
我想我记得早期版本的遗留编译器中的一个错误,它错误解释了类似于块返回类型的隐式转换。
您使用的是哪种编译器? LLVM-GCC 4.2?还是Apple LLVM 4.2?一个旧的编译器? 检查项目的构建设置。我建议切换到Apple LLVM,并检查是否能解决您的问题。
(事实上,LLVM-GCC仅用于从旧GCC到新LLVM的转换,因为现在有一些版本的Xcode,但已被弃用,将在下一版本的Xcode中删除)