不用说大家也都知道.类是对象的抽象,对象是类的实例化.那么,大家有没有去探究过类和对象的底层呢
####首先,什么是类呢
/* Types */
#if !OBJC_TYPES_DEFINED
/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;
/// An opaque type that represents an instance variable.
typedef struct objc_ivar *Ivar;
/// An opaque type that represents a category.
typedef struct objc_category *Category;
/// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t;
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
#endif
OBJC_TYPES_DEFINED
的值是什么我们也不清楚(前年写这个文章的时候确实欠考虑.还好今天的面试让我有机会重新来看看runtime).对于这个值是多少.可以看文章末尾的GitHub上别人整理的苹果runtime文档.在objc-private.h
内有这个宏的定义:
#define OBJC_TYPES_DEFINED 1
然后OBJC_UNAVAILABLE
的值我们是能够在usr/include/objc/objc-api.h
这个头文件里面看得到
/* OBJC2_UNAVAILABLE: unavailable in objc 2.0, deprecated in Leopard */
#if !defined(OBJC2_UNAVAILABLE)
# if __OBJC2__
# define OBJC2_UNAVAILABLE UNAVAILABLE_ATTRIBUTE
# else
/* plain C code also falls here, but this is close enough */
# define OBJC2_UNAVAILABLE \
__OSX_DEPRECATED(10.5, 10.5, "not available in __OBJC2__") \
__IOS_DEPRECATED(2.0, 2.0, "not available in __OBJC2__") \
__TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE
# endif
#endif
简单点说就是objective-C 2.0的时候不受支持.
所以说仅仅只看Xcode的objc文件夹内的内容的话是看不到类的定义的.
在文章底部的资料中我们可以在objc-runtime-new.h
中看到完整的类的定义
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
...
};
下面还有很多内容.如果要看完整的定义的话,需要下载objc-runtime-new.h
文件看看
比如说在使用Class的时候,我们一般都是:
NSObject *object = [NSObject new];
Class class1 = [object class];
//理论上能替换成如下,但是objc_class* 是不对外开放的
objc_class* class2 = [object class];
那么,什么是对象
同理,可以在下面的资料的objc-private.h
中得到
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
...
};
老规矩,篇幅所限,只截取一部分,如果想看整体定义的话,可以在objc-private.h
中找到.
对于这个id:
NSObject* object1 = [NSObject new];
id object2 = [NSObject new];
//也应该等价于
objc_object* object3 = [NSObject new];
在objc中,可以说只要首地址(因为是struct.不是union)是以isa指针开头的
对于上面的类和对象.大家有没有注意一个相同的地方.
对,就是这个Class _Nonnull isa
. 我们说在objc中,只要首地址是isa指针开头的,那这个就是对象.那么Class也是一个对象,等等.不是说Class是类么.
那么就要牵扯到一个元类(MetaClass)的概念了.
类确实是一个对象.是一个元类的对象.
对于meta_class,Apple并没有暴露接口给我们看,但是在runtime.h中我们能够找到,如
/**
- Returns whether an object is a class object.
- @param obj An Objective-C object.
- @return true if the object is a class or metaclass, false otherwise.
- 注意这行话,如果这个对象是一个class或者是metaclass.那么就会返回true
*/
OBJC_EXPORT BOOL
object_isClass(id _Nullable obj)
OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);
以及:objc_getMetaClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
我们可以参考一下上面#if __OBJC2__
里面的内容.这是一个class的定义.里面有:
- super_class:父类.
- name:类名.
- version:版本.
- info:一些类的信息.
- instance_size:类的实例所占内存的大小(对象所占内存大小).
- ivars:成员变量列表.
- methodLists:方法列表
- cache:缓存(方法的缓存,为了下次快速调用).
- protocols:协议列表(知道为什么协议能够多继承了吧).
以上这些东西都是定义在类里头的.那么能够使用这些东西的就是类的实例了咯.
而且我们也可以看出来,对象方法是存储在类中的(属性就不用提了),类中没有属性我们可以猜想元类(metaClass)中并没有存储这些东西
基本上画出来就是上面的这种情况.(male继承与Person.Person继承与NSObject).
根据上图可以看出.所有类的isa指针都不为空.那么任何一个id类型的对象都可以通过isa指针访问该对象的一些信息.
####实例化:
上面说对象是类的实例化.类(类对象)是元类的实例化.
实例对象:当实例化一个类的时候.会拷贝实例对象对应的类的成员变量(其实想一想,new出两个Person,分别为person1,person2.修改person1的比如name属性的时候,person2的name属性总不可能随着person1一起变化吧),但是并不会拷贝类定义的方法.当调用实例方法的时候,会根据实例的isa指针去寻找方法对应的函数指针(这也是为了空间占用率着想,反正这些代码都是固定下来的).
类对象:类对象是没有实例变量的(看看我上面讲的那个两个Person实例对象的例子).但是类中可以存在成员变量.类方法属于类自己,但是存储在元类中.(类对象中存着成员变量与实例方法列表)
#import "Person.h"
@implementation Person
static NSString *str = @"123";
int a;
static int count;
+ (instancetype)person {
NSLog(@"%@",str);
str = @"1231312";
NSLog(@"%@",str);
return [Person new];
}
@end
元类(metaclass):元类中存储着类对象调用的方法("+"类方法).但是我们看不到metaclass(公开的runtimeAPI只能看到有两个方法能够证实metaclass的存在).通过下一篇的clang命令.大家可以在CPP文件里面搜METACLASS
.