【Object-C】对 Object-C 面向对象语法的理解
本文适合其他语言已经有经验,看到 Object-C 的代码觉得 Holly shit 想快速理解的读者Objective-C最大的特色是承自Smalltalk的消息传递模型(message passing) —— 菜鸟教程一个静态语言(如 c),如果代码中没有实现某方法但是程序中存在调用,那么编译器一定会报错;但是实现了消息传递模型的 Object-C 不会,因为调用是发送一条信息,发信息是没有错
本文适合其他语言已经有经验,看到 Object-C 的代码觉得 Holly shit 想快速理解的读者
Objective-C最大的特色是承自Smalltalk的消息传递模型(message passing) —— 菜鸟教程
一个静态语言(如 c),如果代码中没有实现某方法但是程序中存在调用,那么编译器一定会报错;
但是实现了消息传递模型的 Object-C 不会,因为调用是发送一条信息,发信息是没有错的。信息接收者收不到只会导致在程序中抛出异常。
这一最大的不同就导致了 C、java、python 等一系列语言和 Object-C 语言在方法调用风格上的区别。
我们最容易理解的调用形式是:
obj.method(argument);
实例 obj 调用方法 method,参数是 argument
而 Object-C 中却是:
[obj method: argument];
向 obj 的 method 传递信息 argument
其次,这套信息传递的机制只用于面向对象相关的内容。Object-C 是 C 的超集,也就表明 C 中的代码和方法调用的语法仍然可以不经修改正常使用,也就导致最终 Object-C 中中括号的调用机制和正常的调用机制并存的局面。
知道了这两点,下面就只需要明白,基于消息传递模型的方法怎么定义、怎么调用即可。
类和接口的定义
由于这套机制基于面向对象,因此首先仍需要了解类和接口的定义方法。
类/接口的定义包含四部分:
- 头尾区间声明
- 类方法和继承关系声明
- 结构体数据结构定义(Optional)
- 方法定义(Optional)
其中数据结构和方法定义都是可选的,比如下面定义的内容是可以通过的:
#import <Foundation/Foundation.h>
@implementation My : NSObject
@end
int main(int argc, char **argv) {
My *res = [My new]; // 实例创建
}
下面贴一个来自菜鸟教程的一个比较完备的例子(有一些修改):
@interface Myimp : NSObject {
int memberVar1; // 实体变量
id memberVar2;
}
+(return_type) class_method; // 类方法
-(return_type) instance_method1; // 实例方法
@end
@implementation Myimp {
}
+(return_type) class_method {
.... //method implementation
}
-(return_type) instance_method1 {
....
}
@end
基于上面的类创建一个实例,仍然使用信息传递模型:
Myimp *res = [Myimp my];
可以看成是向 类 Myimp 发送了一个
方法定义
类的声明定义完了,之后介绍类中的方法如何定义
下面定义的所有方法(带+/- 号的)都省略了在类上下文,都是仅在类的定义中才能用的。同时,假设类名为 Myimp
区分接口和实现
接口和实现的区别只差一个实现
下面是两个最简单形式的接口和相应实现的代码,可以看到接口在方法声明完后直接 ;
,而实现还会有具体的逻辑代码。
- (void)func:(int)a :(float)b;
- (void)func:(int)a asd:(float)b {
}
为了节省空间,下面只用接口的代码演示定义和调用过程。
无参数
无参数方法最容易理解了:
- (void)func;
调用也很好理解:
Myimp *res = [Myimp my];
[res func];
一个参数
从有参数开始,多了一个冒号
@interface My : NSObject
- (void)func:(int)a;
@end
调用也会多一个冒号:
[res func:5];
仍然还比较好理解
多个参数
多个参数就会有多个冒号,但除了多出一个冒号,还可以多出额外的一些内容,比如对参数的说明。
以下两种声明都是正确的:
- (void)func:(int)a :(float)b;
- (void)func:(int)a toB:(float)b;
但是对不同的声明,调用方式会有区别:
- (void)func:(int)a :(float)b;
[res func:5 :6];
- (void)func:(int)a toB:(float)b;
[res func:5 toB:6];
我们会发现,从第二个参数开始,我们可以对每个参数加一个额外的词(注释?key?需要调研一下官方怎么叫)。
从表现上,可以把函数声明中的 toB 看成是消息传递时的 key,这个 key 只能在调用时用,在方法体内用类型之后的那个参数名,比如:
- (void)func:(int)a toB:(float)b toC:(double)c {
printf("%f%f%f", a, b, c);
}
但即使有了这个 key,在调用时也必须按参数定义顺序来调用:
[res func:3 toB:4 toC:5];
变长参数
暂时没遇到使用场景,偷个懒,随便放个介绍链接,以后填坑。
https://blog.csdn.net/weidfyr/article/details/48263315
Reference
- https://blog.teamtreehouse.com/the-beginners-guide-to-objective-c-methods
- https://www.runoob.com/w3cnote/objective-c-tutorial.html

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。
更多推荐
所有评论(0)