在Objective-C中,为什么是[object doSomething]?既然你在对象上调用一个方法,那不是[*object doSomething]了吗?,这意味着你应该取消对指针的引用?

推荐答案

答案可以追溯到Objective-C的C根.Objective-C最初是作为C的编译器预处理器编写的.也就是说,Objective-C不是编译的,而是转换成直接的C,然后编译的.

从类型id的定义开始.声明如下:

typedef struct objc_object {
    Class isa;
} *id;

也就是说,id是指向第一个字段为Class类型的 struct 的指针(其本身是指向定义类的 struct 的指针).现在,考虑NSObject:

@interface NSObject <NSObject> {
    Class   isa;
}

请注意,NSObject的布局和id所指类型的布局是相同的.这是因为,实际上,Objective-C对象的实例实际上只是指向一个 struct 的指针,该 struct 的第一个字段(始终是指针)指向包含该实例的方法的类(以及其他一些元数据).

当您将NSObject子类化并添加一些实例变量时,出于所有意图和目的,您只需创建一个新的C struct ,其中包含您的实例变量,作为该 struct 中连接到所有超类的实例变量插槽上的插槽.(现代运行时的工作方式有slightly种不同,因此一个超类可以附加IVAR,而无需重新编译所有子类).

现在,考虑这两个变量之间的差异:

NSRect foo;
NSRect *bar;

(NSRect是一个简单的C struct ——不涉及ObjC).foo与堆栈上的存储一起创建.一旦堆栈框架关闭,它将无法存活,但您也不必释放任何内存.bar是对NSRect struct 的引用,该 struct 很可能是使用malloc()在堆上创建的.

如果你想说:

NSArray foo;
NSArray *bar;

编译器会抱怨第一个,说一些与stack based objects are not allowed in Objective-C类似的话.换句话说,必须从堆中分配all个Objective-C对象(或多或少——有一个或两个例外,但它们对本文的讨论相对来说比较深奥),因此,您always通过堆上所述对象的地址引用对象;您总是使用指向对象的指针(id类型实际上只是指向任何旧对象的指针).

回到语言的C预处理器根,您可以将每个方法调用转换为等效的C行.例如,以下两行代码是相同的:

[myArray objectAtIndex: 42];
objc_msgSend(myArray, @selector(objectAtIndex:), 42);

类似地,一个声明如下的方法:

- (id) objectAtIndex: (NSUInteger) a;

等价于如下声明的C函数:

id object_at_index(id self, SEL _cmd, NSUInteger a);

objc_msgSend(),第一个参数被声明为id类型:

OBJC_EXPORT id objc_msgSend(id self, SEL op, ...);

这就是为什么不使用*foo作为方法调用的目标.通过上面的形式进行转换——对[myArray objectAtIndex: 42]的调用被转换为上面的C函数调用,然后它必须使用等价的C函数调用声明(都用方法语法修饰)调用某些东西.

执行对象引用是因为它让messenger——objc_msgSend()访问该类,然后找到方法实现——以及该引用,然后成为最终执行的方法的第一个参数——self.

如果你真的想深入,start here.但是,在你完全掌握grokked this之前不要操心.

Objective-c相关问答推荐

使用 NSMutableString 附加到文件的末尾

如何用零填充左侧的整数?

核心数据 - 如何获取具有最大值属性的实体

在 10.9 上以编程方式启用对辅助设备的访问

静态和动态单元格的 UITableView 混合?

UITextField 中的文本在编辑后向上移动(编辑时居中)

如果用户禁用了应用程序的推送,是否可以进行静默远程通知?

更改 UIBarButtonItem 的 Tint colored颜色

检测代码是否在 Objective-C 的主线程上运行的正确方法是什么? (iOS)

UITabBar 未在 ios 7 中显示所选项目图像

如何在Objective C(NSRegularExpression)中编写正则表达式?

UIKeyboardBoundsUserInfoKey 已弃用,改用什么?

主队列上的 dispatch_sync 与 dispatch_async

如何在 NSSet 或 NSArray 中搜索具有特定属性的特定值的对象?

判断是否已实现可选协议方法

在 DEBUG 模式下启用和禁用 NSLog

以编程方式设置 UIView 的自动调整大小掩码?

如何在没有死锁的情况下同步调度主队列?

Xcode中私有方法的单元测试

如何设置字体大小以填充 UILabel 高度?