iOS 类、对象、属性与方法
此篇文章涉及到Objective-C中对象相关的概念,期望可以把它们串起来,形成对它们总体的认识!
# 对象
所有Objective-C对象都是C语言结构体objc_object,都包含一个isa指针:
```
/// 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:
```
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 存储了当前类在编译期就已经确定的属性、 实例变量 、方法以及遵循的协议。
```
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 存储了当前类在运行期的属性、方法以及遵循的协议。
```
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 分类与扩展 。