class ,struct与object
class是类,struct是结构体。
什么是类?具有相同特性(数据元素)和行为(功能)的对象的抽象就是类。类是一种抽象的数据类型,为所有的对象定义了抽象的属性与行为。类具有属性,它是对象的状态的抽象,用数据结构来描述类的属性。类具有操作,它是对象的行为的抽象,用操作名和实现该操作的方法来描述。
什么是结构体?由一系列具有相同类型或不同类型的数据构成的数据集合,叫做结构。结构被用来代表一个记录,比如一本书,有标题,作者, 主题,图书ID,这就是一个结构。
而在Objective-C中,类在Objective-C中是objc_class
结构体指针。
typedef struct objc_class *Class;
在objc/runtime.h
中objc_class
结构体的定义如下:
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const charchar *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;
isa
: 指向元类的objc_class
结构体指针,iOS中的类也是对象,元类中储存有类对象的类方法;
superclass
: 指向父类的objc_class
结构体指针,如果该类已经是最顶层的根类(如NSObject
或NSProxy
),则superclass
为NULL
,可以通过父类的指针找到变量和方法;
name
:类名;
version
:版本号,默认为0
info
:其他信息,运行期间的一些位标示
instance_size
:类实例变量大小
ivars
: 该类的成员变量链表,是objc_ivar_list
结构体指针
struct objc_ivar_list {
int ivar_count;
/* variable length structure */
struct objc_ivar ivar_list[1];
}
objc_var
:变量结构体---名称,类型,偏移字节和占用的空间
struct objc_ivar {
charchar *ivar_name OBJC2_UNAVAILABLE;
charchar *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}
objc_method_list
: 方法链表结构体
struct objc_method_list {
struct objc_method_list *obsolete OBJC2_UNAVAILABLE;
int method_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_method method_list[1] OBJC2_UNAVAILABLE;
}
method
: 对象的每个方法的结构体,SEL
是方法选择器,是hash后的值,是一个字符串,可以很快地通过这个值找到函数体的实现,IMP
是函数指针
struct objc_method {
SEL method_name OBJC2_UNAVAILABLE;
charchar *method_types OBJC2_UNAVAILABLE;
IMP method_imp OBJC2_UNAVAILABLE;
}
cache
: 对象使用过的方法链表
struct objc_cache {
unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method buckets[1] OBJC2_UNAVAILABLE;
};
protocols
:协议链表
struct objc_protocol_list {
struct objc_protocol_list *next;
long count;
Protocol *list[1];
};
objc_class
的定义中,在使用runtime以class为前缀的方法时,主要就是针对这个struct中的各个字段的。
isa指针
在OC中所有的类其实也是一个对象,那么这个对象也会有一个所属的类,这个类就是元类也就是结构体里面isa指针所指的类。(元类的定义:元类就是类对象的类。每个类都有自己的元类,因为每个类都有自己独一无二的方法。)
1.对象的isa指针指向所属的类
2.类的isa指针指向了所属的元类
3.元类的isa指向了根元类,根元类指向了自己。
有这样一幅图展示这样一种关系:
成员变量(ivars)及属性
在objc_class
中,所有的成员变量、属性的信息是放在链表ivars中的。ivars是一个数组,数组中每个元素是指向Ivar(变量信息)的指针。runtime提供了丰富的函数来操作这一字段。大体上可以分为以下几类:
1.成员变量操作函数:
// 获取类中指定名称实例成员变量的信息
Ivar class_getInstanceVariable ( Class cls, const char *name );
// 获取类成员变量的信息
Ivar class_getClassVariable ( Class cls, const char *name );
// 添加成员变量
BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
// 获取整个成员变量列表
Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
Objective-C不支持往已存在的类中添加实例变量,可以通过runtime
class_addIvar
函数来添加,只能在objc_allocateClassPair
与objc_registerClassPair
之间调用。
另外,这个类也不能是元类。成员变量的按字节最小对齐量是1<<alignment
。这取决于ivar
的类型和机器的架构。如果变量的类型是指针类型,则传递log2(sizeof(pointer_type))
。
2.属性操作函数
// 获取指定的属性
objc_property_t class_getProperty ( Class cls, const char *name );
// 获取属性列表
objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
// 为类添加属性
BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
// 替换类的属性
void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
methodLists方法
objc_method_list方法链表中存放的是该类的成员方法
// 添加方法
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
// 获取实例方法
Method class_getInstanceMethod ( Class cls, SEL name );
// 获取类方法
Method class_getClassMethod ( Class cls, SEL name );
// 获取所有方法的数组
Method * class_copyMethodList ( Class cls, unsigned int *outCount );
// 替代方法的实现
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
// 返回方法的具体实现
IMP class_getMethodImplementation ( Class cls, SEL name );
IMP class_getMethodImplementation_stret ( Class cls, SEL name );
// 类实例是否响应指定的selector
BOOL class_respondsToSelector ( Class cls, SEL sel );
类与结构体的主要区别是struct
是Value Type
,就是值类型, class
是Reference Type
,是引用类型。(在swift里,要想用它的方法修改属性数据,就必须在方法前面加上mutating
关键词。结构体和枚举都是值类型的,默认情况下,值类型的属性是不能从它的实例方法内部改变的。如果想要在实例方法里面修改结构体或者枚举的属性值的话,就需要使用mutating
关键词特殊处理。带有mutating
关键词标志的方法,可以在方法内部修改这些值,并且方法返回后还有效,class
没有这个限制。)
对象是啥?
对象其实就是实例化的类。
对象是一种结构,它包含值和指向其类的隐藏指针。“实例”是对象的另一种称呼,例如,Circle对象也可以称呼为Circle类的实例。
编写面向对象的程序时,你所创建的类和对象之间存在一定的关系,它们协同工作才能实现程序的相应功能。
处理类和对象之间的关系,尤其要重视OOP的两个方面。第一个方面是继承。创建一个新类时,通常需要定义新类以区别于其他类及现有类。使用继承可以定义一个具有父类所有功能的新类,它继承了父类的这些功能。你也可以添加额外的方法以及重写现有的方法来达到你所要实现的功能。
另一个和类有关的OOP技术是复合(composition)。在复合中,对象可以引用其他对象,可以利用其他对象提供的特性,这就是复合。复合是通过包含作为实例变量的指针实现的。
严格的讲,只有对象间的组合才能叫做复合,诸如int、float、enum和struct等基本类型都被认为是对象的一部分。
刚才是主要介绍了iOS的类,结构体,对象的关系。在实际应用过程中,我们可能会对某个类增加方法或者变量。
这时我们就要知道分类Category
和Extension
。