(本文所运行的Demo是在集成了objc4源码基础上的,详见:gitHub)
本文所写的项目详见:OCBasicDemo
基本概念
- OC对象的分类
- instance对象(实例对象)
- class对象(类对象)
- meta-class对 象(元类对象)
1.instance对象
- instance对象就是通过alloc出来的对象,每次调用alloc都会开辟新的内存,都会产生新的instance对象(实例对象)
先定义一个Person自定义的类对象
@interface Person : NSObject{
@public
int _age;
int _number;
}
@end
@implementation Person
@end
---------使用--------
int main(int argc, const char * argv[]) {
@autoreleasepool {
//instance对象
Person *p1 = [[Person alloc]init];
p1->_age = 10;
p1->_number = 100;
Person *p2 = [[Person alloc]init];
p2->_age = 12;
p2->_number = 90;
NSLog(@"%p",p1);//0x1005222a0
NSLog(@"%p",p2);//0x1005220b0
NSLog(@"%p",&(p1->_age)); //0x1005222a8
NSLog(@"%p",&(p1->_number)); //0x1005222ac
NSLog(@"%p",&(p2->_age)); //0x1005220b8
NSLog(@"%p",&(p2->_number)); //0x1005220bc
NSLog(@"End");
}
return 0;
}
- p1和p2是Person的instance对象(实例化出来的)
- 他们所占不同的内存空间(根据他们打印的内存地址就可以看出)
分析:- p1的首地址和p2的首地址不一样
- p1的_age地址和p1的首地址(相差8个字节)(0x1005222a8-0x1005222a0)
- p1的_number地址在_age地址之后排的(加4个字节)
- p2的_age地址和p2的首地址(相差8个字节)(0x1005220b0-0x1005220b8)
查看内存:
image
我们发现:上述描述的结论
使用:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o myMain.cpp
转为C\C++代码:
struct Person_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
double _height;
};
struct NSObject_IMPL {
Class isa;
};
我们可以推测出下面的图:(instance对象的初结构)

- instance对象在内存中存储的信息包括
- isa(这里我们暂且将它定为isa,在后面的章节会具体的分析社么是isa以及isa的作用)
- 其他的成员变量
2.class
- 我们叫它为:类对象
- 我们在main函数里面写入下面的代码(这里xcode运行的环境是objc4-750的源码编译环境git)
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1);
Class objectClass4 = object_getClass(object2);
Class objectClass5 = [NSObject class];
NSLog(@"%p %p",object1,object2);//0x101803170 0x101804f60
NSLog(@"%p %p %p %p %p",
objectClass1,//0x100b14140
objectClass2,//0x100b14140
objectClass3,//0x100b14140
objectClass4,//0x100b14140
objectClass5);//0x100b14140
NSLog(@"End");
}
return 0;
}
发现:
- objectClass1~objectClass5的内存地址都是一样的(也就是说是同一个东西),他们都是NSObject的class对象(类对象)
- 每个类在内存中有且只有一个类对象
接下来我们来代码分析下:
点击Class进入系统的库(这里不是自己集成的objc4-750的哟),发现是:
*typedef struct objc_class Class;
再次点击:objc_class进入
发现:
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;
从这个里面我们可以看到:
一个类信息里面包含的东西如下:

点击Class进入自己集成的objc4-750的源文件里面
1.点击Class----------->
typedef struct objc_class *Class;
2.点击 objc_class进入----------->
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
class_rw_t *data() {
return bits.data();
}
//此处省略代码...
3.点击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;
//此处省略代码...
4.点击class_ro_t----------->
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;
}
};
从源码里面:我们也可以找到对应的信息
3.meta-class(元类)
- 在main.m函数里面
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSObject *object1 = [[NSObject alloc] init];
Class objectClass1 = [object1 class];
Class objectClass2 = object_getClass(object1);
Class objectClass3 = [NSObject class];
// meta-class对象,元类对象
// 将类对象当做参数传入,获得元类对象
Class objectMetaClass1 = object_getClass(objectClass1);
Class objectMetaClass2 = object_getClass(objectClass2);
Class objectMetaClass3 = object_getClass(objectClass3);
NSLog(@"%p %p %p",
objectClass1,//0x100b14140
objectClass2,//0x100b14140
objectClass3 //0x100b14140
);
NSLog(@"%p %p %p",
objectMetaClass1,//0x100b140f0
objectMetaClass2,//0x100b140f0
objectMetaClass3 //0x100b140f0
);
//class方法返回的一直是class对象(类对象)
Class objectMetaClass4 = [[[NSObject class] class] class];
NSLog(@"%p",objectMetaClass4);//0x100b14140
NSLog(@"End");
}
return 0;
}
- 发现objectMetaClass1~objectMetaClass3 他们是同一个
- objectMetaClass1是NSObject的meta-class的对象(元类对象)
- 每一个类在内存中有且只有一个meta-class对象
- meta-class对象和class对象的内存结构是一样的,只是他们不同的用途不一样(见后章节:会有细讲)
- 在内存中主要存储的信息:
- isa指针
- superclass指针
- 类的方法信息 (classMethods)
- ...(等)
补充:
我们在objc的NSObject.mm文件里面看到(或者通过command+鼠标左键,进入打断点可知)
//类的class方法
+ (Class)class {
return self;
}
//实例对象的class方法
- (Class)class {
return object_getClass(self);
}
在object-class.mm文件里面(或者通过command+鼠标左键,进入打断点可知)
//方法 object_getClass
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
分析:
1.
Class objectMetaClass4 = [[[NSObject class] class] class];
NSLog(@"%p",objectMetaClass4);//0x100b14140
分析:
NSObject是一个类对象,所以它掉的是+Class方法,调用class方法,一直返回的是自己(类对象)
2.
Class objectMetaClass4 = [[[object1 class] class] class];
NSLog(@"%p",objectMetaClass4);//0x100b14140
分析:
object1是一个实例对象,调用-Class方法,它返回的是一个类对象(object_getClass(self)),然后类对象继续调用+Class,+Class,最终和上面的结果一致,返回的永远是类对象
由上我们可知:(+/-)class方法返回的一直是class对象(类对象)
4.查看Class是否为meta-class
BOOL result1 = class_isMetaClass([object1 class]);
BOOL result2 = class_isMetaClass([NSObject class]);
BOOL result3 = class_isMetaClass(object_getClass(([NSObject class])));
NSLog(@"%d %d %d",
result1,//0
result2,//0
result3 //1
);
分析:result1、result2 方法返回的永远是类对象,所以他们永远也不是元类对象
result3:传入的是类对象,返回的是元类对象
5.objc_getClass方法
这里我们先记住结论:(后面会在内存章节会具体的分析底层原理)
Class object_getClass(id obj)
1> 传入的obj可能是instance对象、class对象、meta-class对象
2> 返回值
a) 如果是instance对象,返回class对象
b) 如果是class对象,返回meta-class对象
c) 如果是meta-class对象,返回NSObject(基类)的meta-class对象
6:定义一个自定义对象来看
@interface Person:NSObject
@endz
@implementation Person
@end
Person *p = [[Person alloc]init];//0x102141190
Class pClass = object_getClass(p);//0x1000011f8
Class metaPClass = object_getClass(pClass);//0x1000011d0
BOOL res = class_isMetaClass(metaPClass);//1
NSLog(@"%p %p %p %d",p,pClass,metaPClass,res);
友情链接:
网友评论