iOS中对象的本质

我们都知道Object-C是在C\C++的基础上演化而来的,即Object-C底层还是C\C++,然后再经过汇编转换成机器语言,最后被计算机CPU所识别。

那么,我们平时写的类、对象会转换成C\C++什么数据结构类型呢?

首先,我们新建一个项目,并在项目中简单写上

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSObject *obj = [[NSObject alloc] init];
    }
    return 0;
}

通过点击NSObject可以进入其定义头文件中,可以发现NSObject的定义是:

@interface NSObject <NSObject> {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-interface-ivars"
    Class isa  OBJC_ISA_AVAILABILITY;
#pragma clang diagnostic pop
}

简化后,NSObject的定义可以写成如下格式

@interface NSObject {
    Class isa  OBJC_ISA_AVAILABILITY;
}

通过头文件观察,并不能够观察出什么,然后我们借助clang编译器指令:
clang -rewrite-objc main.m -o main.cpp
该指令可以将main.m文件转换为C\C++代码main.cpp。

其中,rewrite-objc是重写objc语言;main.m是需要重写的文件;-o 是输出;main.cpp输出目标文件

更多学习关于clang常用语法介绍

以上转换方式,只是单存的转换为C\C++代码,并没有指明编译平台,对此,我们可以使用xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp将main.m文件转换为iphoneos下的arm64平台下的.cpp文件。该指令会对原有指令进行响应优化。

其中xcrun是xcode run的意思;-sdk iphoneos是编译在iphoneos平台;在-arch arm64中arch是architectures构架的意思,arm64是苹果所用的构架中的一种其他还包括:arm7、arm7s等
更多学习关于iOS 中的 armv7,armv7s,arm64,i386,x86_64 都是什么

在转化完的main.cpp文件中,我们可以找到如下代码:

其中,IMPL为implementation;NSObject_IMPL即为NSObject的实现,isa其实是“is a”是一个的意思。Class可以通过进入,查看其的定义为typedef struct objc_class *Class;,可以看出其为一个指向结构体类型的指针。

因此,NSObject对象,在定义为

@interface NSObject {
    Class isa  OBJC_ISA_AVAILABILITY;
}

格式的情况下,通过内部一系列操作,最终转换为C\C++底层的代码为:

struct NSObject_IMPL {
	Class isa;
};

通过观察可知NSObject_IMPL为一个结构体。
因此,NSObject对象底层实际上是一个内部有一个isa指针的结构体

OC对象、类主要是基于C\C++的结构体实现的

更深的挖掘可以看出一下关系图:

在这里插入图片描述

OC对象的分类:

Objective-C中的对象分为三类:instance对象、class对象、meta-class对象

  • instance对象(实例对象):通过类alloc出来的对象,每次调用alloc都会产生新的instance对象;
    所有的对象都是继承NSObject,通过以上分析,我们可知在instance里面有一个isa指针,和其他的成员变量

  • class对象(类对象):class对象只有一个
    class对象在内存中存储的信息主要包括:
    isa指针
    superclass指针
    类的属性信息(@property)、类的对象方法信息(instance method)
    类的协议信息(protocol)、类的成员变量信息(ivar)

通过查看源文件,我们可以看到 struct objc_class 的定义:
在这里插入图片描述
虽然我们拿到的定义已经OBJC2_UNAVAILABLE了,但是依然可以看出class里面的内容:
简化后分析可得:

typedef struct objc_class *Class;

struct objc_class {
    Class  isa ;  								 // isa
    Class  super_class ;						 //super_class指针,指向meta-class
    const char * name;   						 //类的名字                          
    long version;
    long info;
    long instance_size;							//instances对象占用的内存空间
    struct objc_ivar_list *  ivars;				//成员变量列表
    struct objc_method_list * *  methodLists;//方法列表
    struct objc_cache *  cache;					//缓存
    struct objc_protocol_list *  protocols;     //协议列表
} ;

当然,你也可以看下新的定义:

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();
    }

};

Class对象,是一个结构体
结构体里面有继承struct objc_class : objc_object
结构体里面还有方法
OC中的结构体,其实是C++中的结构体,C++中的结构体与类相似,几乎没有区别

学习写C++中的结构体与类
学习C++

  • meta-class对象(元类对象)
    从class内部的super_class指针类型可知,元类的类型也是Class,即元类对象与类对象的结构是一样的。

可以看下图查看它们的关系:

在这里插入图片描述
在这里插入图片描述

注:1. 第二张关系图中,虚线上的class更改为isa可能更好理解一些 2. 第二张关系图中RootClass中没有superclass是不对的 3.第二张关系图中isa、superclass前面是不带*的,因为Class本身就是指针。第二张图中的错误真是。。。

总结:

每一个实例对象里面都有一个isa指针,指向class类对象;

每一个class类对象里面有一个isa指针,指向metaclass元类对象;
每一个class类对象里面有一个superclass指针,指向其父类的class类对象;其父类的class类对象里面也有一个superclass指针,指向根类对象;根类对象中的superclass指针为nil(而不是第二张图中的没有);

每一个metaclass元类对象里面有一个superclass指针,指向其父类的metaclass元类对象;最终指向RootMetaClass,RootMetaClass的superclass指针指向NSObject,即根类
每一个metaclass元类对象有一个isa指针,指向根元类对象;根元类对象的isa指针指向自己;

class类对象中的objc_method_list为对象方法;
metaclass元类中存放的objc_method_list是类方法;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值