一、指针内存偏移
1)指针地址
a)普通指针(值拷贝)
看到两个变量赋值一个常量,答应值和地址时,值一样地址不一样,对于此称之为值拷贝;&a 的意思是,指向这个变量的地址。b)对象(指针拷贝)
此时对象的内存空间完全不一样,是因为在alloc的过程了两个对象申请的是不同的内存空间,&p1 的意思是,指向这个对象指针的地址。c)数组指针
上图想表达的就是,打印的第一个和第一个地址是一样,因为数组的首地址就是数组的第一个元素的地址,跟打印对象内存空间时,内存的首地址就是对象的地址一个道理。2)指针偏移
这里的 d, d+1, d+2,就是对指针地址偏移的实际运用,打印的结果就代表数组三个元素的地址,每个地址相差 4 ,是因为这个数组为 int 型。通过对比,通过下标取值和通过指针内存偏移再取值得到的结果都相同。
通过打印数组首地址的到这个数组的内存空间,再读取值所在的内存段,也可以打印出来,为什么内存里面显示的顺序为,2,1,3 ?因为iOS为小端模式。
希望通过以上分析,对理解指针内存偏移有所帮助。
二、类的结构 先打印看下类的内存空间
如图我已经将几个前面提到的地址打印出来并知道代表什么了,那剩下的几个是代表什么?一起往下分析对要分析的文件clang一下,我这里是 main.m ,clang 一下就是 main.cpp,然后并打开它。
还是直接划到最底部,这次从main函数开始分析,这张图片的代码内存是跟上面那张是对应的,OC 编译为 C++.这部分既然是对类的结构分析,那么就在main.cpp中查找一下 Class 的定义看是什么样,见下图
原来Class的真正类型为 objc_class;还有直接在项目里不用clang,直接选中 Class 点进去,也可以看到这个结果,再找一下 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();
}
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);
}
bool hasCustomRR() {
return ! bits.hasDefaultRR();
}
void setHasDefaultRR() {
assert(isInitializing());
bits.setHasDefaultRR();
}
void setHasCustomRR(bool inherited = false);
void printCustomRR(bool inherited);
bool hasCustomAWZ() {
return ! bits.hasDefaultAWZ();
}
void setHasDefaultAWZ() {
assert(isInitializing());
bits.setHasDefaultAWZ();
}
void setHasCustomAWZ(bool inherited = false);
void printCustomAWZ(bool inherited);
bool instancesRequireRawIsa() {
return bits.instancesRequireRawIsa();
}
void setInstancesRequireRawIsa(bool inherited = false);
void printInstancesRequireRawIsa(bool inherited);
bool canAllocNonpointer() {
assert(!isFuture());
return !instancesRequireRawIsa();
}
bool canAllocFast() {
assert(!isFuture());
return bits.canAllocFast();
}
bool hasCxxCtor() {
// addSubclass() propagates this flag from the superclass.
assert(isRealized());
return bits.hasCxxCtor();
}
void setHasCxxCtor() {
bits.setHasCxxCtor();
}
bool hasCxxDtor() {
// addSubclass() propagates this flag from the superclass.
assert(isRealized());
return bits.hasCxxDtor();
}
void setHasCxxDtor() {
bits.setHasCxxDtor();
}
bool isSwiftStable() {
return bits.isSwiftStable();
}
bool isSwiftLegacy() {
return bits.isSwiftLegacy();
}
bool isAnySwift() {
return bits.isAnySwift();
}
// 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;
}
#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() {
return data()->flags & RW_REALIZED;
}
// Returns true if this is an unrealized future class.
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isFuture() {
return data()->flags & RW_FUTURE;
}
bool isMetaClass() {
assert(this);
assert(isRealized());
return data()->ro->flags & RO_META;
}
// NOT identical to this->ISA when this is a metaclass
Class getMeta() {
if (isMetaClass()) return (Class)this;
else return this->ISA();
}
bool isRootClass() {
return superclass == nil;
}
bool isRootMetaclass() {
return ISA() == (Class)this;
}
const char *mangledName() {
// fixme can't assert locks here
assert(this);
if (isRealized() || isFuture()) {
return data()->ro->name;
} else {
return ((const class_ro_t *)data())->name;
}
}
const char *demangledName(bool realize = false);
const char *nameForLogging();
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceStart() {
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() {
return word_align(unalignedInstanceStart());
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
size_t instanceSize(size_t 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());
if (newSize != data()->ro->instanceSize) {
assert(data()->flags & RW_COPIED_RO);
*const_cast<uint32_t *>(&data()->ro->instanceSize) = newSize;
}
bits.setFastInstanceSize(newSize);
}
void chooseClassArrayIndex();
void setClassArrayIndex(unsigned Idx) {
bits.setClassArrayIndex(Idx);
}
unsigned classArrayIndex() {
return bits.classArrayIndex();
}
};
嗯,好多。还是从头看,原来 objc_class 是继承于 objc_object,万物皆对象,其实 objc_class 也是一种对象,从这句代码就可以说明。
// Class ISA;:在这个结构体开始出有一个隐藏的isa,那为什么是隐藏的呢?
因为这个isa 来自继承,也就是来自 objc_object(下图)
这其实就标明了,最后的大 boss 就是 objc_object ,那跟之前有提到的跟元类和根根元类的NSObject 是什么关系呢?然后又看一下 NSObject 的源码并贴出来 好吧,objc_object 和 NSObject 的内部结构都一样的,都是 Class isa还记得这部分开始解析时,打印了类的内存结构,刚才还有几个地址并不知道代表的是什么,根据下图,类的结构源码便可知
0x100001468 :首地址指向的是 isa0x001d800100001441:isa
0x0000000100b36140:superclass
0x100001478:此首地址指向的是 cache
0x00000001003d9260:cache
0x0000000000000000: bits
但是我们看都第四段还有感觉不太对,全是0,其实它存的东西是很对,所以后面再进行分析。
根据以上,对class的类型和结构就有个大概的了解了。
补充:
1)objc_class 和 NSObject 的关系?
NSObject 是 objc_class 的类型,因为 NSObject 也是一个 class。
2)objc_objce 和 NSObject 的关系?
任何的上层代码是OC,OC底层封装的就是C,objc_objce 是NSObject的底层实现,也就是本质。