我们知道,在实例方法中,self指的是类实例,而在类方法中, self指的是类,而不是类实例,一般情况下也是可以直接将self换成类名来调用。类实例是由类名来创建的,那类是怎么来的呢,类都是源自于一个叫元类。
类可以看做其元类的实例,与此同时,我们再看objc 对象对应的结构体。
struct objc_class {
Class isa; // 指向所属类的指针(_Nonnull)
Class super_class; // 父类
const char *name; // 类名(_Nonnull)
long version; // 类的版本信息(默认为0)
long info; // 类信息(供运行期使用的一些位标识)
long instance_size; // 该类的实例变量大小
struct objc_ivar_list *ivars; // 该类的成员变量链表
struct objc_method_list * *methodLists; // 方法定义的链表
struct objc_cache *cache; // 方法缓存
struct objc_protocol_list *protocols; // 协议链表
};
*methodLists 储存改对象方法的列表,如果了解Objective-C的运行时机制,一个类实例调用方法,会在该类中的方法表中检索。也就是改methodLists,但并不一定能找到,如果不能找到,如图会沿着链路逐层向父类查找,也就是在父类中的methodLists查找,如果都找不到,则会按照消息传递的逻辑进行。同理一个类的变量也是存在ivars 中,如果没有,则会在父类的ivars 中查找。
目前Objective-C 也引入了类属性,用法是在property的修饰符中加入class,代表这是一个类的属性。在原来Person.h 添加
@property (nonatomic, copy, class) NSString *name;
在很多类属性当中,并不需要设置实例属性,因为每个实例都会创建一遍,开辟一段内存。事实上,对于类属性来说,一个类只要一个实例就行了。
但是在使用类属性时也需要注意,使用方法仍然比较繁琐,
static NSString *className = @"PersonName";
@implementation Persion
+ (NSString *)name {
return className;
}
+ (void)setName:(NSString *)name {
className = name
}
注意的地方
都应该使用“+” 表示这是一个类方法,同时声明一个static 静态变量来存储,类属性本身不提供存储。类方法的使用可以更好地在类中声明合适的属性,
小结
类实例对象是由类实例化得到的,而类是由其元类得到的,因此可以看做元类的实例。
了解类属性,可以直接通过类直接访问,但需要手动添加setter,getter 方法以及实例变量。