8

在这段代码中

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)

4

3 回答 3

3

您正在为块文字使用推断的返回类型,但您不必这样做。

消除该错误的正确方法是为块文字提供返回类型:

id (^block)(void) = ^id{
    return nil;
};
于 2013-06-15T23:15:02.887 回答
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*which 不断衰减,直到它到达void*,或“任何通用指针”(根据 C 语言规范)。void* 和 id 肯定不是同一类型。为了解决这个问题,你必须向编译器保证返回的类型是真实的,唯一的方法就是强制转换。

LLVM 5.0 通过使编译器的推理更加智能来解决这个问题。

于 2013-06-15T19:59:46.210 回答
0

我不知道为什么 nil#define nil NULL在 Apple 标头中(这是事实,但我不知道为什么它不像(id)0人们所期望的那样),但我从来没有遇到过你在最新版本的 Xcode 和编译器。

我想我记得旧版编译器的早期版本中有一个错误,它误解了块返回类型和所有内容中的隐式强制转换。

您使用的是哪个编译器?LLVM-GCC 4.2?还是苹果 LLVM 4.2?较旧的编译器?检查项目的构建设置。我建议切换到 Apple LLVM,并检查是否能解决您的问题

(事实上​​,LLVM-GCC 仅用于从旧 GCC 到新 LLVM 的转换,因为现在有一些 Xcode 版本,但已弃用,将在下一个 Xcode 版本中删除)

于 2013-06-15T11:14:42.163 回答