其他文章请点击下方:
实例对象、类对象、元类之间的关系
类对象只会在内存里存在一份
XLPerson *p = [[XLPerson alloc] init];//实例对象
Class class1= [XLPerson class]; //类对象
Class class2= p.class;//类对象
Class class3= object_getClass(p);//类对象
NSLog(@"\n%p-\n%p-\n%p",class1,class2,class3); //结果是同一个指针
Class class4= object_getClass(class3); //元类
实例对象
由类初始化出来的对象就是实例对象。
类对象
通过元类实例化出来的对象就是类对象。
元类
类对象所属的类,系统自动实现。 元类的归属是根元类。
Isa
是一个联合体,为了节省内存消耗。 数据共享一块内存。 是存在我们的类里。
private:
isa_t isa;
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
优化isa:普通的isa&ISA_MASK
经曲isa走位图:

注: 根元类的父类是NSOjbect,NSObject的父类是nil
类结构
struct objc_class : objc_object {
// Class ISA; // 8
Class superclass; // 8
cache_t cache; // 16 // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
void setInfo(uint32_t set) {
assert(isFuture() || isRealized());
data()->setFlags(set);
}
.....
}
执行 class_data_bits_t 结构体中的 data() 方法会返回同一个 class_rw_t * 指针,ObjC 类中的属性、方法还有遵循的协议等信息都保存在 class_rw_t 中。
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
其中还有一个指向常量的指针 ro,其中存储了当前类在编译期就已经确定的属性、方法以及遵循的协议。
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;
method_list_t *baseMethods() const {
return baseMethodList;
}
};
方法
实例方法获取
Method method1 = class_getInstanceMethod([XLPerson class], @selector(xl_instanceMethod)); // 类对象拿实例方法
Method method2 = class_getInstanceMethod(objc_getMetaClass("XLPerson"), @selector(xl_instanceMethod)); // 元类对象拿实例方法
Method method3 = class_getInstanceMethod([XLPerson class], @selector(xl_classMethod));//类对象拿类方法
Method method4 = class_getInstanceMethod(objc_getMetaClass("XLPerson"), @selector(xl_classMethod));//元类对象拿类方法
NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
结果1和4有值,2和3没有值。 这也得出来一个结论:
- 类方法存在我们的元类中。
- 对象实例方法存在我们的类中。
方法实现获取
IMP imp1 = class_getMethodImplementation([XLPerson class], @selector(xl_instanceMethod));
IMP imp2 = class_getMethodImplementation([XLPerson class], @selector(xl_classMethod));
IMP imp3 = class_getMethodImplementation(objc_getMetaClass("XLPerson"), @selector(xl_instanceMethod));
IMP imp4 = class_getMethodImplementation(objc_getMetaClass("XLPerson"), @selector(xl_classMethod));
NSLog(@"%p-%p-%p-%p",imp1,imp2,imp3,imp4);
结果都有值,但2和3通过系统进行消息转发,看下面源码:
IMP class_getMethodImplementation(Class cls, SEL sel)
{
IMP imp;
if (!cls || !sel) return nil;
imp = lookUpImpOrNil(cls, sel, nil,
YES/*initialize*/, YES/*cache*/, YES/*resolver*/);
// Translate forwarding function to C-callable external version
if (!imp) {
return _objc_msgForward;//消息转发
}
return imp;
}
类方法获取
Method method1 = class_getClassMethod([XLPerson class], @selector(xl_instanceMethod));
Method method2 = class_getClassMethod(objc_getMetaClass("XLPerson"), @selector(xl_instanceMethod));
Method method3 = class_getClassMethod([XLPerson class], @selector(xl_classMethod));
Method method4 = class_getClassMethod(objc_getMetaClass("XLPerson"), @selector(xl_classMethod));
NSLog(@"%p-%p-%p-%p",method1,method2,method3,method4);
很显然,1和2是没有值的,但3和4是有结果,而且结果是一样的。这是两种获取类方法的写法,看源码实现:
/***********************************************************************
* class_getClassMethod. Return the class method for the specified
* class and selector.
**********************************************************************/
Method class_getClassMethod(Class cls, SEL sel)
{
if (!cls || !sel) return nil;
return class_getInstanceMethod(cls->getMeta(), sel);
}
元类获取的类方法等价于类获取的类方法。
协议\属性\方法
method_array_t methods;
property_array_t properties;
protocol_array_t protocols;
class method_array_t :
public list_array_tt<method_t, method_list_t>
{
typedef list_array_tt<method_t, method_list_t> Super;
public:
method_list_t **beginCategoryMethodLists() {
return beginLists();
}
method_list_t **endCategoryMethodLists(Class cls);
method_array_t duplicate() {
return Super::duplicate<method_array_t>();
}
};
class property_array_t :
public list_array_tt<property_t, property_list_t>
{
typedef list_array_tt<property_t, property_list_t> Super;
public:
property_array_t duplicate() {
return Super::duplicate<property_array_t>();
}
};
class protocol_array_t :
public list_array_tt<protocol_ref_t, protocol_list_t>
{
typedef list_array_tt<protocol_ref_t, protocol_list_t> Super;
public:
protocol_array_t duplicate() {
return Super::duplicate<protocol_array_t>();
}
};
方法、协议、属性都是继承的list_array_tt,所以添加方法、协议、属性都是通过attachLists这个函数实现的。
void attachLists(List* const * addedLists, uint32_t addedCount) {
if (addedCount == 0) return;
if (hasArray()) {
// many lists -> many lists
uint32_t oldCount = array()->count;
uint32_t newCount = oldCount + addedCount;
setArray((array_t *)realloc(array(), array_t::byteSize(newCount)));
array()->count = newCount;
memmove(array()->lists + addedCount, array()->lists,
oldCount * sizeof(array()->lists[0]));
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
else if (!list && addedCount == 1) {
// 0 lists -> 1 list
list = addedLists[0];
}
else {
// 1 list -> many lists
List* oldList = list;
uint32_t oldCount = oldList ? 1 : 0;
uint32_t newCount = oldCount + addedCount;
setArray((array_t *)malloc(array_t::byteSize(newCount)));
array()->count = newCount;
if (oldList) array()->lists[addedCount] = oldList;
memcpy(array()->lists, addedLists,
addedCount * sizeof(array()->lists[0]));
}
}
此方法会加载类、分类、添加属性、添加方法、添加协议的时候调用
/***********************************************************************
* methodizeClass
* Fixes up cls's method list, protocol list, and property list.
* Attaches any outstanding categories.
* Locking: runtimeLock must be held by the caller
**********************************************************************/
static void methodizeClass(Class cls)
{
runtimeLock.assertLocked();
bool isMeta = cls->isMetaClass();
auto rw = cls->data();
auto ro = rw->ro;
// Methodizing for the first time
if (PrintConnecting) {
_objc_inform("CLASS: methodizing class '%s' %s",
cls->nameForLogging(), isMeta ? "(meta)" : "");
}
// Install methods and properties that the class implements itself.
method_list_t *list = ro->baseMethods();
if (list) {
prepareMethodLists(cls, &list, 1, YES, isBundleClass(cls));
rw->methods.attachLists(&list, 1);
}
property_list_t *proplist = ro->baseProperties;
if (proplist) {
rw->properties.attachLists(&proplist, 1);
}
protocol_list_t *protolist = ro->baseProtocols;
if (protolist) {
rw->protocols.attachLists(&protolist, 1);
}
// Root classes get bonus method implementations if they don't have
// them already. These apply before category replacements.
if (cls->isRootMetaclass()) {
// root metaclass
addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO);
}
// Attach categories.
category_list *cats = unattachedCategoriesForClass(cls, true /*realizing*/);
attachCategories(cls, cats, false /*don't flush caches*/);
if (PrintConnecting) {
if (cats) {
for (uint32_t i = 0; i < cats->count; i++) {
_objc_inform("CLASS: attached category %c%s(%s)",
isMeta ? '+' : '-',
cls->nameForLogging(), cats->list[i].cat->name);
}
}
}
if (cats) free(cats);
#if DEBUG
// Debug: sanity-check all SELs; log method list contents
for (const auto& meth : rw->methods) {
if (PrintConnecting) {
_objc_inform("METHOD %c[%s %s]", isMeta ? '+' : '-',
cls->nameForLogging(), sel_getName(meth.name));
}
assert(sel_registerName(sel_getName(meth.name)) == meth.name);
}
#endif
}