-1

考虑:

[self.staves enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    HBStaffView * sv = (HBStaffView *) obj ;
    [sv flush] ;
}] ;

和:

[self.staves enumerateObjectsUsingBlock:^(HBStaffView * sv, NSUInteger idx, BOOL *stop) {
    [sv flush] ;
}] ;

两者都可以编译,并且都可以工作。

我知道我正在枚举的数组中有什么,因此编译器为我完成了正确类型的转换,以便将正确的类型直接传递给我,我需要如何使用它显然是一个福音。

有趣的是,这里的块签名是一个“C”语言签名,与选择器无关,并且(理论上)对对象一无所知,当然不是“id”是所有事物的超类(所以说话松散)。

嗯?注释?

4

3 回答 3

4

您的两段代码之间实际上没有区别。

enumerateObjectsUsingBlock:方法被声明为将块作为参数,其中块参数为(id, NSUInteger, BOOL*)。您可以将其声明为更具体的对象类型(MyClass*, NSUInteger, BOOL*)这只是 Objective-C 的一个特性;只要更具体的类型是某种 Objective-C 实例引用,它就允许用更具体的类型说明符代替参数。id

块是 C 语言特性是无关紧要的。C 函数也是如此,但您也可以将对象类型传递给 C 函数。事实上,Objective-C 方法实际上只是一个开头总是有两个参数的 C 函数。 self_cmd(尝试NSLog(@"%@", NSStringFromSelector(_cmd));任何方法)。

于 2013-05-17T16:02:31.223 回答
2

语法可能是 C 语法,但类型id是 Objective-C 类型。你不能在编译为严格 C 而不是 Objective-C 的东西中使用该块签名,除非,也许你添加一个 typedefid来表示void*

于 2013-05-17T16:09:21.383 回答
-1

实际上,它与所有事物NSObject的超类(idis NSObject*)这一事实有关。因为HBStaffView继承自NSObject您可以将第二个版本视为第一个版本的特化。另一方面,如果原始签名需要 NSNumber 并且您尝试使用 NSString 则代码将无法编译。转换仅在编译时是“不安全的”。如果数组中的对象不是您声明的类型,那么一旦您调用该对象的方法,就会在运行时引发异常。

- - 编辑 - -

我站得更正了。id,正如@Codify 所说,它不像objc_object NSObject* * 可能暗示的那样声明。该文件提到

id 类型定义了一个通用对象指针。声明变量时可以使用 id ,但是您会丢失有关该对象的编译时信息。

这可以简单地解释为任何类型的对象。其余的解释仍然有效。

于 2013-05-17T15:24:42.697 回答