精彩文章免费看

iOS 类、对象、属性与方法

此篇文章涉及到Objective-C中对象相关的概念,期望可以把它们串起来,形成对它们总体的认识!

# 对象

所有Objective-C对象都是C语言结构体objc_object,都包含一个isa指针:

objc.h

```

/// An opaque type that represents an Objective-C class.

typedef struct objc_class * Class;

/// Represents an instance of a class.

struct objc_object {

Class isa  OBJC_ISA_AVAILABILITY;

```

#

所有Objective-C类都是C语言结构体objc_class,继承自objc_object:

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

class_rw_t *data () {

return bits.data();

... // 其他方法

```

class_data_bits_t的定义:

```

// data pointer

#define FAST_DATA_MASK          0x00007ffffffffff8UL

struct class_data_bits_t {

// Values are the FAST_ flags above.

uintptr_t bits;

public:

class_rw_t * data() {

return (class_rw_t * )(bits & FAST_DATA_MASK);

void setData(class_rw_t * newData)

assert( ! data() || (newData -> flags & (RW_REALIZING | RW_FUTURE)));

// Set during realization or construction only. No locking needed.

bits = (bits & ~ FAST_DATA_MASK) | (uintptr_t)newData;

# 类的属性、方法、协议

##class_ro_t 存储了当前类在编译期就已经确定的属性、 实例变量 、方法以及遵循的协议。

代码 objc-runtime-new.h

```

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;

```

baseMethodList:存储类实现的方法;

baseProtocols:存储类遵循的协议;

ivars:存储类的实例变量,关于Ivar可见: iOS Ivar

baseProperties:存储类的属性;

编译期class_ro_t在对象中的位置:


##class_rw_t 存储了当前类在运行期的属性、方法以及遵循的协议。

代码 objc-runtime-new.h

```

struct class_rw_t {

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;

void setFlags (uint32_t set)

OSAtomicOr32Barrier(set, & flags);

void clearFlags (uint32_t clear)

OSAtomicXor32Barrier(clear, & flags);

// set and clear must not overlap

void changeFlags (uint32_t set, uint32_t clear)

assert((set & clear) == 0);

uint32_t oldf, newf;

oldf = flags;

newf = (oldf | set) & ~ clear;

} while ( ! OSAtomicCompareAndSwap32Barrier(oldf, newf, ( volatile int32_t * ) & flags));

methods:存储类实现的方法;

properties:存储类的属性;

protocols:存储类遵循的协议;

运行期class_rw_t及class_ro_t在对象中的位置:


##class_rw_t class_ro_t 的关系

class_ro_t存放的是在编译期间就确定的;

class_rw_t是在运行期才确定,当运行runtime的realizeClass方法后,会先将class_ro_t的内容拷贝过去,然后再将当前类的分类的方法拷贝到其中。所以可以说class_rw_t是class_ro_t的超集,当然实际访问类的方法、属性等也都是访问class_rw_t中的内容。

在运行期添加方法时,会修改class_rw_t的methods列表,而不是class_ro_t中的baseMethods。

## 实例变量在对象内存中的布局

例子代码:

```

// XXObject.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface XXObject : NSObject

int _int0;

@property ( nonatomic , assign ) int int1;

@property ( nonatomic , assign ) int int2;

@property ( nonatomic , assign ) int int3;

NS_ASSUME_NONNULL_END

// XXObject.m

#import "XXObject.h"

@implementation XXObject

- ( instancetype ) init

if (self = [super init]) {

_int0 = 3;

return self;

// main.m

int main( int argc, const char * argv[]) {

@autoreleasepool {

// Setup code that might create autoreleased objects goes here.

XXObject * obj = [[XXObject alloc] init];

obj.int1 = 4;

obj.int2 = 5;

obj.int3 = 6;

// 此处加断点

return 0;

```

# 方法调用

下面是Objective-C中的经典图,不但说明isa的关系,也表明了方法查找的路径。

## 调用实例方法

缓存命中

查找当前类的缓存及方法

查找父类的缓存及方法

方法决议

消息转发

调用类方法的区别是在元类中查找,其他与调用实例方法是一样的。具体可参考: 从源代码看 ObjC 中消息的发送 - 面向信仰编程

#分类的方法

在运行期,dyld完成对OC镜像的符号绑定后,会把分类的实例方法、协议添加到class_rw_t的methods列表和protocols列表上,也会把分类的类方法和协议添加到类的元类上。具体可见: iOS 分类与扩展

最后编辑于:2021-12-01 11:42