深挖OC中的类与对象

不用说大家也都知道.类是对象的抽象,对象是类的实例化.那么,大家有没有去探究过类和对象的底层呢


####首先,什么是类呢

/* Types */

#if !OBJC_TYPES_DEFINED

/// An opaque type that represents a method in a class definition.
typedef struct objc_method *Method;

/// An opaque type that represents an instance variable.
typedef struct objc_ivar *Ivar;

/// An opaque type that represents a category.
typedef struct objc_category *Category;

/// An opaque type that represents an Objective-C declared property.
typedef struct objc_property *objc_property_t;

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 *` */

#endif

OBJC_TYPES_DEFINED的值是什么我们也不清楚(前年写这个文章的时候确实欠考虑.还好今天的面试让我有机会重新来看看runtime).对于这个值是多少.可以看文章末尾的GitHub上别人整理的苹果runtime文档.在objc-private.h内有这个宏的定义:

#define OBJC_TYPES_DEFINED 1

然后OBJC_UNAVAILABLE的值我们是能够在usr/include/objc/objc-api.h这个头文件里面看得到

/* OBJC2_UNAVAILABLE: unavailable in objc 2.0, deprecated in Leopard */
#if !defined(OBJC2_UNAVAILABLE)             
#   if __OBJC2__
#       define OBJC2_UNAVAILABLE UNAVAILABLE_ATTRIBUTE
#   else
        /* plain C code also falls here, but this is close enough */
#       define OBJC2_UNAVAILABLE                                       \
            __OSX_DEPRECATED(10.5, 10.5, "not available in __OBJC2__") \
            __IOS_DEPRECATED(2.0, 2.0, "not available in __OBJC2__")   \
            __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE 
#   endif
#endif

简单点说就是objective-C 2.0的时候不受支持.

所以说仅仅只看Xcode的objc文件夹内的内容的话是看不到类的定义的.

在文章底部的资料中我们可以在objc-runtime-new.h中看到完整的类的定义

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
    ...
};

下面还有很多内容.如果要看完整的定义的话,需要下载objc-runtime-new.h文件看看

比如说在使用Class的时候,我们一般都是:

NSObject *object = [NSObject new];
Class class1 = [object class];
//理论上能替换成如下,但是objc_class* 是不对外开放的
objc_class* class2 = [object class];
那么,什么是对象

同理,可以在下面的资料的objc-private.h中得到

struct objc_object {
private:
    isa_t isa;
public:
    // ISA() assumes this is NOT a tagged pointer object
    Class ISA();
    // getIsa() allows this to be a tagged pointer object
    Class getIsa();
    ...
};

老规矩,篇幅所限,只截取一部分,如果想看整体定义的话,可以在objc-private.h中找到.

对于这个id:

NSObject* object1 = [NSObject new];
id object2 = [NSObject new];
//也应该等价于
objc_object* object3 = [NSObject new];
在objc中,可以说只要首地址(因为是struct.不是union)是以isa指针开头的

对于上面的类和对象.大家有没有注意一个相同的地方.
对,就是这个Class _Nonnull isa. 我们说在objc中,只要首地址是isa指针开头的,那这个就是对象.那么Class也是一个对象,等等.不是说Class是类么.
那么就要牵扯到一个元类(MetaClass)的概念了.
类确实是一个对象.是一个元类的对象.

对于meta_class,Apple并没有暴露接口给我们看,但是在runtime.h中我们能够找到,如
/**

  • Returns whether an object is a class object.
  • @param obj An Objective-C object.
  • @return true if the object is a class or metaclass, false otherwise.
  • 注意这行话,如果这个对象是一个class或者是metaclass.那么就会返回true
    */
    OBJC_EXPORT BOOL
    object_isClass(id _Nullable obj)
    OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);
    以及:objc_getMetaClass(const char * _Nonnull name)
    OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);

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 *` */

我们可以参考一下上面#if __OBJC2__里面的内容.这是一个class的定义.里面有:

  1. super_class:父类.
  2. name:类名.
  3. version:版本.
  4. info:一些类的信息.
  5. instance_size:类的实例所占内存的大小(对象所占内存大小).
  6. ivars:成员变量列表.
  7. methodLists:方法列表
  8. cache:缓存(方法的缓存,为了下次快速调用).
  9. protocols:协议列表(知道为什么协议能够多继承了吧).
    以上这些东西都是定义在类里头的.那么能够使用这些东西的就是类的实例了咯.
    而且我们也可以看出来,对象方法是存储在类中的(属性就不用提了),类中没有属性我们可以猜想元类(metaClass)中并没有存储这些东西

这里写图片描述
基本上画出来就是上面的这种情况.(male继承与Person.Person继承与NSObject).
根据上图可以看出.所有类的isa指针都不为空.那么任何一个id类型的对象都可以通过isa指针访问该对象的一些信息.

####实例化:

上面说对象是类的实例化.类(类对象)是元类的实例化.

实例对象:当实例化一个类的时候.会拷贝实例对象对应的类的成员变量(其实想一想,new出两个Person,分别为person1,person2.修改person1的比如name属性的时候,person2的name属性总不可能随着person1一起变化吧),但是并不会拷贝类定义的方法.当调用实例方法的时候,会根据实例的isa指针去寻找方法对应的函数指针(这也是为了空间占用率着想,反正这些代码都是固定下来的).
类对象:类对象是没有实例变量的(看看我上面讲的那个两个Person实例对象的例子).但是类中可以存在成员变量.类方法属于类自己,但是存储在元类中.(类对象中存着成员变量与实例方法列表)

#import "Person.h"

@implementation Person

static NSString *str = @"123";

int a;

static int count;

+ (instancetype)person {
    NSLog(@"%@",str);
    str = @"1231312";
    NSLog(@"%@",str);
    return [Person new];
}

@end

元类(metaclass):元类中存储着类对象调用的方法("+"类方法).但是我们看不到metaclass(公开的runtimeAPI只能看到有两个方法能够证实metaclass的存在).通过下一篇的clang命令.大家可以在CPP文件里面搜METACLASS.

GitHub上某人整理的苹果runtime项目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值