ios对象本质是转换为c++的结构体
- 可以把main函数编译为c++的文件
- 跳转到
mian
函数的文件位置
cd /Users/ruicong/Desktop/oc对象的本质/oc的本质/oc的本质/
2.编译mian
为c++文件
clang -rewrite-objc main.m -o main.cpp
如果报错
使用 xcrun命令,
-sdk
是指定平台的为iphoneos
, -arch
是指定架构为arm64
,-rewrite-objc
指定重新的文件为main.m
文件,-o
表示输出的文件地方
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
NSObject对象的本质是NSObject_IMPL
结构体,这个结构体只有一个成员isa
一个
NSObject
对象占用的多少内存
- 系统分配了16个字节给NSObject对象(通过malloc_size函数获取),但是NSObject对象内部只使用了8个字节的空间(arm64下,可以通过class_getInstanceSize函数获得)
#import <malloc/malloc.h>
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import <malloc/malloc.h>
#import <objc/runtime.h>
//nsobjcectimplementation
struct NSObject_IMPL {
Class isa;
};
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
NSObject * objc = [[NSObject alloc]init];
NSInteger size = malloc_size((__bridge void *)objc);
NSInteger size1 = class_getInstanceSize([NSObject class]);
}
NSLog(@"Hello Word");
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
- 在程序中打一个端点,获取到对象的地址,然后在xcode中
Debug--debug Workflow--viewMemory
中输入的对象的内存地址
内存地址
地址是16进制的,一位16进制数,用4位二进制数表示,两位就是8位进制数,8位二进制是一个字节,下面表示出来(红框)的是16个字节
内存地址图片
常用的LLDB指令
-
print
,p
:打印 -
po
: 打印对象 -
读取内存
-
memory read
读取内存,可以简写为x
memory read 0x2827ac000
x 0x2827ac000
- 修改内存地址的值,
memory write
修改第九个字节为09,原来是00
memory write 0x2827ac009 09
从19开始为0,开始往后面数就是内存地址一个个的0x2827ac001,0x2827ac002,直到0x2827ac009
0x2827ac000: 19 72 62 d8 a1 01 00 00 00 09 00 00 00 00 00 00 .rb.............
- 带有格式的读取方式
memory read/数量格式字节数 内存地址
x/数量格式字节数 内存地址
格式
x是16进制,f是浮点,d是10进制
字节大小
b:byte 1字节,h:half word 2字节
w:word 4字节,g:giant word 8字节
x/4xg 0x2827ac000
0x2827ac000: 0x000001a1d8627219 0x0000000000000900
0x2827ac010: 0x0000000000000000 0x0000000000000000
4个数量,16进制的格式,4个字节(是16进制格式,一个位16进制数是4位二进制数,2个16进制数,是8位二进制数,8位二进制是一个字节,两位16进制数占用一个字节)
x/4xw 0x2827ac000
0x2827ac000: 0xd8627219 0x000001a1 0x00000900 0x00000000
高字节和低字节
- 0x1234 其中12就是数据的高字节部分,34就是低字节部分
cpu的大小端
- 小端模式:
低地址存放是数据的低字节数据,高地址存放的是字节数据的高字节 - 大端模式:
字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中。 大小端分布图
所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
ios cpu都是小端模式
内存地址
这个是小端模式,存储的数据应该是这样的
0x000001A1040F5649
0x00000004
0x00000005
结构体内存对齐
结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节
oc对象的最小的内存大小是16个字节
因为结构体里面有个isa指针,这个指针是8个字节的,所需要的内存大小,必须能够被8整除,所有最少得16个字节,不足的在后面用字节补齐
实例对象,在内存中存储的是自己的成员变量
NSObject * objc = [[NSObject alloc]init];
NSObject * objc1 = [[NSObject alloc]init];
这两个实例对象创建出来的实例对象的指针地址是不一样的
NSLog(@"%p,%p",objc,objc1);
2021-06-29 18:24:15.086998+0800 oc的本质[1263:580933] 0x280190100,0x280190110
类对象,类对象在内存中只有一份
Class classobjc = objc_getClass([@"NSObject" UTF8String]);
Class classobjc1 = [NSObject class];
Class classobjc2 = [objc class];
Class classobjc3 = object_getClass(objc);
NSLog(@"%p,%p,%p,%p",classobjc,classobjc1,classobjc2,classobjc3);
注意:object_getClass(objc);
方法中,传入的是实例对象,获得才是类对象,如果里面传入的是类对象或者类,获得的是元类对象
2021-06-29 20:29:12.227673+0800 oc的本质[1308:609002] 0x1f5fcb248,0x1f5fcb248,0x1f5fcb248,0x1f5fcb248
元类对象,每个类只有一个元类对象
- 将类对象或者类当做参数传入,获得元类对象
Class objectMetaClass = object_getClass([NSObject class]);
Class objectMetaClass1 = object_getClass(classobjc2);
2021-06-29 20:37:03.850001+0800 oc的本质[1314:610924] 0x1f5fcb220,0x1f5fcb220
类对象存储的信息
class对象在内存中存储的信息主要包括
isa指针
superclass指针
类的属性信息(@property)、类的对象方法信息(instance method)
类的协议信息(protocol)、类的成员变量信息(ivar)
这里的成员变量信息:不是存储的什么值,而是指的是成员变量的类型和成员变量名字是什么
元类对象存储的信息
meta-class对象和class对象的内存结构是一样的,但是用途不一样,在内存中存储的信息主要包括
isa指针
superclass指针
类的类方法信息(class method)
isa指针
- instance(实例对象)的
isa
指向class(类对象)
当调用对象方法
时,通过instance的isa
找到class
,最后找到对象方法
的实现进行调用 - class(类对象)的
isa
指向meta-class(元类对象)
当调用类方法
时,通过class的isa
指针找到meta-class
,最后找到类方法的实现进行调用
superclass指针
有一个Student类继承Person类,Person类继承NSObject
- 当
Student
的instance对象要调用Student
类的对象方法时,会先通过isa
找到Student的类对象,然后找到对象方法进行调用 - 当
Student
的instance对象调用Person
的对象方法时,会先通过isa
指针找到Student的类对象(class),然后通过Student的类对象的superclass
找到Person的类对象,最后找到对象方法的实现进行调用
isa、superclass总结
- instance的isa指向class
- class的isa指向meta-class
- meta-class的isa指向基类的meta-class
- class的superclass指向父类的class
- 如果没有父类,superclass指针为nil
- meta-class的superclass指向父类的meta-class
-
基类的meta-class的superclass指向基类的class
isa指针和superclass指针
通过isa指针获取到类的地址
p/x就是以16进制形式进行打印
- 要想通过实例对象的isa指针,存储的地址就是类对象的地址,就得在isa指针上&上一个ISA_MASK的偏移量 isa_mask
JGPerson * person1 = [[JGPerson alloc]init];
Class personClass1 = [JGPerson class];
- 获取person1的isa指针的地址
p/x person1->isa
(Class) $0 = 0x000021a10283d9a9 JGPerson
- 获取类对象的地址
p/x personClass1
(Class) $1 = 0x000000010283d9a8 JGPerson
- isa指针地址&上isa_mask的偏移量
p/x 0x000021a10283d9a9 & 0x0000000ffffffff8ULL
(unsigned long long) $2 = 0x000000010283d9a8
isa_mask偏移量去掉ULL
也可以的
p/x 0x000021a10283d9a9 & 0x0000000ffffffff8
(long) $3 = 0x000000010283d9a8
类对象的isa指针,指向元类对象
- 直接用类对象直接取里面的isa指针,会报错
p/x personClass1->isa
error: <user expression 4>:1:13: member reference base type 'Class' is not a structure or union
personClass1->isa
~~~~~~~~~~~~^ ~~~
- 可以自己写个结构体,与系统的样式一样的
struct JG_objc_class{
Class isa;
};
- 然后用类对象赋值这个给个结构体对象
Class personClass1 = [JGPerson class];
struct JG_objc_class * personClass3 = (__bridge struct JG_objc_class *)(personClass1);
- 获取metaclass对象
Class personClass2 = [JGPerson class];
Class personMetaClass = object_getClass(personClass2);
- 获取结构体中isa指针
p/x personClass3->isa
(Class) $0 = 0x0000000100dad980
- 获取metaclass的指针
p/x personMetaClass
(Class) $1 = 0x0000000100dad980
- 类对象的isa指针&上isa_mask的偏移量
p/x 0x0000000100dad980 & 0x0000000ffffffff8ULL
(unsigned long long) $3 = 0x0000000100dad980
superclass指向父类
struct JG_objc_class{
Class isa;
Class super_class;
};
struct JG_objc_class * student3 = (__bridge struct JG_objc_class *)([JGStudent class]);
Class personClass1 = [JGPerson class];
p/x student3->super_class
(Class) $0 = 0x00000001028c59a8 JGPerson
p/x personClass1
(Class) $2 = 0x00000001028c59a8 JGPerson
可以验证student的类对象的super_class指针,指向的是JGPerson的类对象的地址
验证类对象(class对象)和元类对象(meta对象)里面存放的信息
- 要想验证类的信息,从源码中可以看到包含的信息
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 *` */
但是这些信息在OBJC2.0就不起作用了,无效了,那只能从objc4-818.2
这个源码进行查找,
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// 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 getSuperclass() const {
#if __has_feature(ptrauth_calls)
# if ISA_SIGNING_AUTH_MODE == ISA_SIGNING_AUTH
if (superclass == Nil)
return Nil;
#if SUPERCLASS_SIGNING_TREAT_UNSIGNED_AS_NIL
void *stripped = ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
if ((void *)superclass == stripped) {
void *resigned = ptrauth_sign_unauthenticated(stripped, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
if ((void *)superclass != resigned)
return Nil;
}
#endif
void *result = ptrauth_auth_data((void *)superclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
return (Class)result;
# else
return (Class)ptrauth_strip((void *)superclass, ISA_SIGNING_KEY);
# endif
#else
return superclass;
#endif
}
void setSuperclass(Class newSuperclass) {
#if ISA_SIGNING_SIGN_MODE == ISA_SIGNING_SIGN_ALL
superclass = (Class)ptrauth_sign_unauthenticated((void *)newSuperclass, ISA_SIGNING_KEY, ptrauth_blend_discriminator(&superclass, ISA_SIGNING_DISCRIMINATOR_CLASS_SUPERCLASS));
#else
superclass = newSuperclass;
#endif
}
class_rw_t *data() const {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
void setInfo(uint32_t set) {
ASSERT(isFuture() || isRealized());
data()->setFlags(set);
}
void clearInfo(uint32_t clear) {
ASSERT(isFuture() || isRealized());
data()->clearFlags(clear);
}
// set and clear must not overlap
void changeInfo(uint32_t set, uint32_t clear) {
ASSERT(isFuture() || isRealized());
ASSERT((set & clear) == 0);
data()->changeFlags(set, clear);
}
#if FAST_HAS_DEFAULT_RR
bool hasCustomRR() const {
return !bits.getBit(FAST_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
bits.setBits(FAST_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
bits.clearBits(FAST_HAS_DEFAULT_RR);
}
#else
bool hasCustomRR() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_RR);
}
void setHasDefaultRR() {
bits.data()->setFlags(RW_HAS_DEFAULT_RR);
}
void setHasCustomRR() {
bits.data()->clearFlags(RW_HAS_DEFAULT_RR);
}
#endif
#if FAST_CACHE_HAS_DEFAULT_AWZ
bool hasCustomAWZ() const {
return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
void setHasDefaultAWZ() {
cache.setBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
cache.clearBit(FAST_CACHE_HAS_DEFAULT_AWZ);
}
#else
bool hasCustomAWZ() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_AWZ);
}
void setHasDefaultAWZ() {
bits.data()->setFlags(RW_HAS_DEFAULT_AWZ);
}
void setHasCustomAWZ() {
bits.data()->clearFlags(RW_HAS_DEFAULT_AWZ);
}
#endif
#if FAST_CACHE_HAS_DEFAULT_CORE
bool hasCustomCore() const {
return !cache.getBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
void setHasDefaultCore() {
return cache.setBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
void setHasCustomCore() {
return cache.clearBit(FAST_CACHE_HAS_DEFAULT_CORE);
}
#else
bool hasCustomCore() const {
return !(bits.data()->flags & RW_HAS_DEFAULT_CORE);
}
void setHasDefaultCore() {
bits.data()->setFlags(RW_HAS_DEFAULT_CORE);
}
void setHasCustomCore() {
bits.data()->clearFlags(RW_HAS_DEFAULT_CORE);
}
#endif
#if FAST_CACHE_HAS_CXX_CTOR
bool hasCxxCtor() {
ASSERT(isRealized());
return cache.getBit(FAST_CACHE_HAS_CXX_CTOR);
}
void setHasCxxCtor() {
cache.setBit(FAST_CACHE_HAS_CXX_CTOR);
}
#else
bool hasCxxCtor() {
ASSERT(isRealized());
return bits.data()->flags & RW_HAS_CXX_CTOR;
}
void setHasCxxCtor() {
bits.data()->setFlags(RW_HAS_CXX_CTOR);
}
#endif
#if FAST_CACHE_HAS_CXX_DTOR
bool hasCxxDtor() {
ASSERT(isRealized());
return cache.getBit(FAST_CACHE_HAS_CXX_DTOR);
}
void setHasCxxDtor() {
cache.setBit(FAST_CACHE_HAS_CXX_DTOR);
}
#else
bool hasCxxDtor() {
ASSERT(isRealized());
return bits.data()->flags & RW_HAS_CXX_DTOR;
}
void setHasCxxDtor() {
bits.data()->setFlags(RW_HAS_CXX_DTOR);
}
#endif
#if FAST_CACHE_REQUIRES_RAW_ISA
bool instancesRequireRawIsa() {
return cache.getBit(FAST_CACHE_REQUIRES_RAW_ISA);
}
void setInstancesRequireRawIsa() {
cache.setBit(FAST_CACHE_REQUIRES_RAW_ISA);
}
#elif SUPPORT_NONPOINTER_ISA
bool instancesRequireRawIsa() {
return bits.data()->flags & RW_REQUIRES_RAW_ISA;
}
void setInstancesRequireRawIsa() {
bits.data()->setFlags(RW_REQUIRES_RAW_ISA);
}
#else
bool instancesRequireRawIsa() {
return true;
}
void setInstancesRequireRawIsa() {
// nothing
}
#endif
void setInstancesRequireRawIsaRecursively(bool inherited = false);
void printInstancesRequireRawIsa(bool inherited);
#if CONFIG_USE_PREOPT_CACHES
bool allowsPreoptCaches() const {
return !(bits.data()->flags & RW_NOPREOPT_CACHE);
}
bool allowsPreoptInlinedSels() const {
return !(bits.data()->flags & RW_NOPREOPT_SELS);
}
void setDisallowPreoptCaches() {
bits.data()->setFlags(RW_NOPREOPT_CACHE | RW_NOPREOPT_SELS);
}
void setDisallowPreoptInlinedSels() {
bits.data()->setFlags(RW_NOPREOPT_SELS);
}
void setDisallowPreoptCachesRecursively(const char *why);
void setDisallowPreoptInlinedSelsRecursively(const char *why);
#else
bool allowsPreoptCaches() const { return false; }
bool allowsPreoptInlinedSels() const { return false; }
void setDisallowPreoptCaches() { }
void setDisallowPreoptInlinedSels() { }
void setDisallowPreoptCachesRecursively(const char *why) { }
void setDisallowPreoptInlinedSelsRecursively(const char *why) { }
#endif
bool canAllocNonpointer() {
ASSERT(!isFuture());
return !instancesRequireRawIsa();
}
bool isSwiftStable() {
return bits.isSwiftStable();
}
bool isSwiftLegacy() {
return bits.isSwiftLegacy();
}
bool isAnySwift() {
return bits.isAnySwift();
}
bool isSwiftStable_ButAllowLegacyForNow() {
return bits.isSwiftStable_ButAllowLegacyForNow();
}
uint32_t swiftClassFlags() {
return *(uint32_t *)(&bits + 1);
}
bool usesSwiftRefcounting() {
if (!isSwiftStable()) return false;
return bool(swiftClassFlags() & 2); //ClassFlags::UsesSwiftRefcounting
}
bool canCallSwiftRR() {
// !hasCustomCore() is being used as a proxy for isInitialized(). All
// classes with Swift refcounting are !hasCustomCore() (unless there are
// category or swizzling shenanigans), but that bit is not set until a
// class is initialized. Checking isInitialized requires an extra
// indirection that we want to avoid on RR fast paths.
//
// In the unlikely event that someone causes a class with Swift
// refcounting to be hasCustomCore(), we'll fall back to sending -retain
// or -release, which is still correct.
return !hasCustomCore() && usesSwiftRefcounting();
}
bool isStubClass() const {
uintptr_t isa = (uintptr_t)isaBits();
return 1 <= isa && isa < 16;
}
// Swift stable ABI built for old deployment targets looks weird.
// The is-legacy bit is set for compatibility with old libobjc.
// We are on a "new" deployment target so we need to rewrite that bit.
// These stable-with-legacy-bit classes are distinguished from real
// legacy classes using another bit in the Swift data
// (ClassFlags::IsSwiftPreStableABI)
bool isUnfixedBackwardDeployingStableSwift() {
// Only classes marked as Swift legacy need apply.
if (!bits.isSwiftLegacy()) return false;
// Check the true legacy vs stable distinguisher.
// The low bit of Swift's ClassFlags is SET for true legacy
// and UNSET for stable pretending to be legacy.
bool isActuallySwiftLegacy = bool(swiftClassFlags() & 1);
return !isActuallySwiftLegacy;
}
void fixupBackwardDeployingStableSwift() {
if (isUnfixedBackwardDeployingStableSwift()) {
// Class really is stable Swift, pretending to be pre-stable.
// Fix its lie.
bits.setIsSwiftStable();
}
}
_objc_swiftMetadataInitializer swiftMetadataInitializer() {
return bits.swiftMetadataInitializer();
}
// Return YES if the class's ivars are managed by ARC,
// or the class is MRC but has ARC-style weak ivars.
bool hasAutomaticIvars() {
return data()->ro()->flags & (RO_IS_ARC | RO_HAS_WEAK_WITHOUT_ARC);
}
// Return YES if the class's ivars are managed by ARC.
bool isARC() {
return data()->ro()->flags & RO_IS_ARC;
}
bool forbidsAssociatedObjects() {
return (data()->flags & RW_FORBIDS_ASSOCIATED_OBJECTS);
}
#if SUPPORT_NONPOINTER_ISA
// Tracked in non-pointer isas; not tracked otherwise
#else
bool instancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
ASSERT(isFuture() || isRealized());
return data()->flags & RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS;
}
void setInstancesHaveAssociatedObjects() {
// this may be an unrealized future class in the CF-bridged case
ASSERT(isFuture() || isRealized());
setInfo(RW_INSTANCES_HAVE_ASSOCIATED_OBJECTS);
}
#endif
bool shouldGrowCache() {
return true;
}
void setShouldGrowCache(bool) {
// fixme good or bad for memory use?
}
bool isInitializing() {
return getMeta()->data()->flags & RW_INITIALIZING;
}
void setInitializing() {
ASSERT(!isMetaClass());
ISA()->setInfo(RW_INITIALIZING);
}
bool isInitialized() {
return getMeta()->data()->flags & RW_INITIALIZED;
}
void setInitialized();
bool isLoadable() {
ASSERT(isRealized());
return true; // any class registered for +load is definitely loadable
}
IMP getLoadMethod();
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isRealized() const {
return !isStubClass() && (data()->flags & RW_REALIZED);
}
// Returns true if this is an unrealized future class.
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isFuture() const {
if (isStubClass())
return false;
return data()->flags & RW_FUTURE;
}
bool isMetaClass() const {
ASSERT_THIS_NOT_NULL;
ASSERT(isRealized());
#if FAST_CACHE_META
return cache.getBit(FAST_CACHE_META);
#else
return data()->flags & RW_META;
#endif
}
// Like isMetaClass, but also valid on un-realized classes
bool isMetaClassMaybeUnrealized() {
static_assert(offsetof(class_rw_t, flags) == offsetof(class_ro_t, flags), "flags alias");
static_assert(RO_META == RW_META, "flags alias");
if (isStubClass())
return false;
return data()->flags & RW_META;
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClassMaybeUnrealized()) return (Class)this;
else return this->ISA();
}
bool isRootClass() {
return getSuperclass() == nil;
}
bool isRootMetaclass() {
return ISA() == (Class)this;
}
// If this class does not have a name already, we can ask Swift to construct one for us.
const char *installMangledNameForLazilyNamedClass();
// Get the class's mangled name, or NULL if the class has a lazy
// name that hasn't been created yet.
const char *nonlazyMangledName() const {
return bits.safe_ro()->getName();
}
const char *mangledName() {
// fixme can't assert locks here
ASSERT_THIS_NOT_NULL;
const char *result = nonlazyMangledName();
if (!result) {
// This class lazily instantiates its name. Emplace and
// return it.
result = installMangledNameForLazilyNamedClass();
}
return result;
}
const char *demangledName(bool needsLock);
const char *nameForLogging();
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceStart() const {
ASSERT(isRealized());
return data()->ro()->instanceStart;
}
// Class's instance start rounded up to a pointer-size boundary.
// This is used for ARC layout bitmaps.
uint32_t alignedInstanceStart() const {
return word_align(unalignedInstanceStart());
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() const {
ASSERT(isRealized());
return data()->ro()->instanceSize;
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() const {
return word_align(unalignedInstanceSize());
}
inline size_t instanceSize(size_t extraBytes) const {
if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
return cache.fastInstanceSize(extraBytes);
}
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
void setInstanceSize(uint32_t newSize) {
ASSERT(isRealized());
ASSERT(data()->flags & RW_REALIZING);
auto ro = data()->ro();
if (newSize != ro->instanceSize) {
ASSERT(data()->flags & RW_COPIED_RO);
*const_cast<uint32_t *>(&ro->instanceSize) = newSize;
}
cache.setFastInstanceSize(newSize);
}
void chooseClassArrayIndex();
void setClassArrayIndex(unsigned Idx) {
bits.setClassArrayIndex(Idx);
}
unsigned classArrayIndex() {
return bits.classArrayIndex();
}
};
- 按照系统方法,大神提取出一个文件
//
// MJClassInfo.h
// TestClass
//
// Created by MJ Lee on 2018/3/8.
// Copyright © 2018年 MJ Lee. All rights reserved.
//
#import <Foundation/Foundation.h>
#ifndef MJClassInfo_h
#define MJClassInfo_h
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# endif
#if __LP64__
typedef uint32_t mask_t;
#else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;
struct bucket_t {
cache_key_t _key;
IMP _imp;
};
struct cache_t {
bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
};
struct entsize_list_tt {
uint32_t entsizeAndFlags;
uint32_t count;
};
struct method_t {
SEL name;
const char *types;
IMP imp;
};
struct method_list_t : entsize_list_tt {
method_t first;
};
struct ivar_t {
int32_t *offset;
const char *name;
const char *type;
uint32_t alignment_raw;
uint32_t size;
};
struct ivar_list_t : entsize_list_tt {
ivar_t first;
};
struct property_t {
const char *name;
const char *attributes;
};
struct property_list_t : entsize_list_tt {
property_t first;
};
struct chained_property_list {
chained_property_list *next;
uint32_t count;
property_t list[0];
};
typedef uintptr_t protocol_ref_t;
struct protocol_list_t {
uintptr_t count;
protocol_ref_t list[0];
};
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize; // instance对象占用的内存空间
#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;
};
struct class_rw_t {
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_list_t * methods; // 方法列表
property_list_t *properties; // 属性列表
const protocol_list_t * protocols; // 协议列表
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
};
#define FAST_DATA_MASK 0x00007ffffffffff8UL
struct class_data_bits_t {
uintptr_t bits;
public:
class_rw_t* data() {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
};
/* OC对象 */
struct mj_objc_object {
void *isa;
};
/* 类对象 */
struct mj_objc_class : mj_objc_object {
Class superclass;
cache_t cache;
class_data_bits_t bits;
public:
class_rw_t* data() {
return bits.data();
}
mj_objc_class* metaClass() {
return (mj_objc_class *)((long long)isa & ISA_MASK);
}
};
#endif /* MJClassInfo_h */
- 在main函数中引入这个文件,然后可以调用了
在运行的时候,xcode会报错,因为.m
格式的文件,只能编译oc
和c
的文件,这个文件是c++
的,修改main.m
文件为main.mm
文件 - 获取class的信息
struct mj_objc_class * studentClass4 = (__bridge struct mj_objc_class *)[JGStudent class];
这个c++的结构体,可以向类一样的访问,可以去掉struct
mj_objc_class * studentClass5 = (__bridge mj_objc_class *)[JGStudent class];
- 获取类对象的信息
class_rw_t * studentClassData = studentClass5 ->data();
- 获取元类对象的信息
class_rw_t * studentMetaClassData = studentClass5->metaClass()->data();
-
打印结果为
打印结果
网友评论