1. 类,是一个模板,定义了成员(数据),方法(函数)和关系(继承,接口)。
可以简单理解为一个结构体C,里面定义了这些信息。
对象,也是一个结构体,只是里面拥有一个类型信息的指针,然后该指针的值等于类型信息结构体的地址。对象的类型不同,也就是其类型指针的值的不同,所有类型的数据结构应该是一致的。
--->
@interface NSObject <NSObject> {
Class isa OBJC_ISA_AVAILABILITY;
}
--->
typedef struct objc_class *Class;
--->
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
以上,也可以一窥Object对象的数据结构了。
2.方法信息,对于OC中的方法,乍看起来比较奇怪,其实这样做是合理的。从数据结构上可以看到,可以猜测其实现最后是由OC编译器翻译成了了C语言的进行编译链接成可执行程序的,那么C里面只有函数。其形式大致是之类的形式之类的形式,
int func( int a, double b, char *s );
那么OC方法是,
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
要实现方法的重载,就必须有方法的签名,这里可以根据以上,由OC编译器由以上方法名翻译成两部分:
(1)方法签名,类似与一个字符串一样的东西,[performSelector:withObject:withObject:],其实应该还要带上参数的类型信息。反射机制里面由^$#之类的类型替代符符号等。
(2)方法实现(传统的C函数)int performSelector_...( SEL a,....)之类的C语言函数。
配上合适的(key,value)之类的数据结构,就可以实现面向对象了,这样每次调用函数的时候,OC编译器根据函数名称生成方法签名的key,然查找到函数实现。就可以了。还有一种可能的实现是,静态编译直接调用,那么可以直接根据规生成函数名称,然后由OC编译器生成函数实现。比如以上可以有,
void *performSelector_withObject_withObject( SEL del, ....){ ... return ...}的函数名称,然后实现该函数即可。
多态的实现,如果对象结构的类型信息中含有父类的指针,那么就可以通过该类对象开始向父类按照签名逐级查找就是多态类。因为对象的引用毕竟只是一个指针而已,而对象类型信息的数据结构,肯定是像一个链表一样的数据结构,所以查找肯定也是从该类开始向父类逐级查找,所以多态是天生自然支持的。
注意,以上的理解也是一个大致的理解,只是根据自己已有的经验和知识进行的一个总结,并没有太纠结与实际情况。
3. 题外话
因为C是最接近操作系统结构和运行原理的语言,所以,一些必须的元素是必须要有的,比如方法最后还是函数,函数的话,肯定必须有函数地址,函数参数等。所以,各类语言,个人觉得多数是一个语法糖一样的东西,然后根据不同目的出发点,设计出合理的数据结构,函数调用方式,配上新的语法,然后根据这些来编写一个编译器,就可以推出很多新的语言,比如OC,这些都是一个量变引起质变的过程。
每种新的语言都是一种有目的重新设计。但是,最后都是通过各种桥,翻译成里汇编等可以让机器运行的语言(汇编,01010110111...)。条条道路通罗马。每条路的尽头其实都是同一个目的地。
个人觉得,编程可以不用C,但是必须还是得了解的,万变不离其宗。