day1 day 2
OC 面向对象的本质
- OC实现面向对象的本质是 C++的结构体
@interface MJPerson : NSObject{
int _age;
int _height;
int _no;
}
@end
@interface MJStudent : MJPerson{
int _weight;
}
struct NSObject_IMPL {
Class isa;
};
struct MJPerson_IMPL {
struct NSObject_IMPL NSObject_IVARS;
int _age;
int _height;
int _no;
};
struct MJStudent_IMPL
{
struct MJPerson_IMPL MJPerson_IVARS;
int _weight;
};
通过使用 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Person.m
命令查看编译后的文件, 我们知道当使用 @dynamic
关键字修饰属性时候, 编译器不会默认帮我们生成 对应的setter 和getter和成员变量, 只有一个属性, 如果我们使用@synthesize
或者默认情况, 编译器会帮我们添加对应的setter和getter和成员变量.
内存对齐 :
- 初始化的时候系统分给每个对象的内存 : 16的倍数
- 初始化之后每个对象那个真的占用的内存 : 对象成员变量中占用的内存最大的成员变量的占用内存数的的倍数(剩余的系统分配的但是没有使用的 用 0 填充)
对象的分类
- 实例对象 类对象 元类对象
- 实例对象存储 : isa + 其他成员变量的具体值
- 类对象存储 : isa + superclass + 属性信息 + 对象方法 + 协议 + 成员变量信息(名称, 类型等) + 类方法(null)
- 元类对象存 : isa + superclass + 属性信息(null) + 对象方法(null) + 协议(null) + 成员变量信息(null) + 类方法
NSObject *object1 = [[NSObject alloc] init];
Class objectClass2 = [NSObject class];
// - 获取一个对象的类
Class objectClass3 = object_getClass(object1);
// - 获取一个类的元类
Class objectMetaClass = object_getClass(objectClass2);
// - 说明 : arg 为类时 返回元类, arg 为对象时 返回类
object_getClass(arg)
方法调用的本质
- 在方法调用的时候 会先去对象的 isa 指针所指向的对象中找方法, 如果没有找到这个方法的话,就会去对象的父类中去找方法,如果父类对象中没有这个方法,就会去父类的父类中去找这个方法
- 因为有以上的图 才会出现 以下的状况 - 因为在 MJPerson 这个类中去调用 test 这个类方法时候 会去 MJPerson 的元类中去这个类方法, 发现MJPerson 的元类中没有这个类方法,然后就会去 MJPerson 的元类 的父类 即 NSObject 的元类 中去找这个类方法,发现 NSObject 的元类中也没有这个类方法, 就会去 NSObject 中去找名为 test 的方法 然后在 NSObject 中找到名为 test 的对象方法,所以这个可以调用成功
@interface MJPerson : NSObject
+ (void)test;
@end
@implementation MJPerson
@end
@implementation NSObject (Test)
- (void)test{
NSLog(@"-[NSObject test] - %p", self);
}
@end
- 在 OC 中 对象(类对象, 实例对象, 元类对象)的 superClass指针 都是直接指向父类对象的地址, 但是 isa指针不同 isa & ISA_MASK 才是指向元类对象的地址
由于现在 xcode 中的 runtime 是已经老的版本 现在都开始用了新版本 这里引用小码哥的代码 窥探下新的 runtime 的代码
//
// MJClassInfo.h
// TestClass
//
// Created by MJ Lee on 2018/3/8.
// Copyright © 2018年 MJ Lee. All rights reserved.
//
#import <Foundation/Foundation.h>
#ifndef MJClassInfo_h
#define MJClassInfo_h
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# endif
#if __LP64__
typedef uint32_t mask_t;
#else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;
struct bucket_t {
cache_key_t _key;
IMP _imp;
};
struct cache_t {
bucket_t *_buckets;
mask_t _mask;
mask_t _occupied;
};
struct entsize_list_tt {
uint32_t entsizeAndFlags;
uint32_t count;
};
struct method_t {
SEL name;
const char *types;
IMP imp;
};
struct method_list_t : entsize_list_tt {
method_t first;
};
struct ivar_t {
int32_t *offset;
const char *name;
const char *type;
uint32_t alignment_raw;
uint32_t size;
};
struct ivar_list_t : entsize_list_tt {
ivar_t first;
};
struct property_t {
const char *name;
const char *attributes;
};
struct property_list_t : entsize_list_tt {
property_t first;
};
struct chained_property_list {
chained_property_list *next;
uint32_t count;
property_t list[0];
};
typedef uintptr_t protocol_ref_t;
struct protocol_list_t {
uintptr_t count;
protocol_ref_t list[0];
};
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize; // instance对象占用的内存空间
#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;
};
struct class_rw_t {
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_list_t * methods; // 方法列表
property_list_t *properties; // 属性列表
const protocol_list_t * protocols; // 协议列表
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
};
#define FAST_DATA_MASK 0x00007ffffffffff8UL
struct class_data_bits_t {
uintptr_t bits;
public:
class_rw_t* data() {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
};
/* OC对象 */
struct mj_objc_object {
void *isa;
};
/* 类对象 */
struct mj_objc_class : mj_objc_object {
Class superclass;
cache_t cache;
class_data_bits_t bits;
public:
class_rw_t* data() {
return bits.data();
}
mj_objc_class* metaClass() {
return (mj_objc_class *)((long long)isa & ISA_MASK);
}
};
#endif /* MJClassInfo_h */
使用和窥探
MJStudent *stu = [[MJStudent alloc] init];
stu->_weight = 10;
mj_objc_class *studentClass = (__bridge mj_objc_class *)([MJStudent class]);
mj_objc_class *personClass = (__bridge mj_objc_class *)([MJPerson class]);
class_rw_t *studentClassData = studentClass->data();
class_rw_t *personClassData = personClass->data();
class_rw_t *studentMetaClassData = studentClass->metaClass()->data();
class_rw_t *personMetaClassData = personClass->metaClass()->data();
主动调用KVO
[self.model.name willChangeValueForKey:@"now"];
[self.model.name didChangeValueForKey:@"now"];
KVC 的 setValue:forKey: 和 ValueForKey 的底层原理
- setValue:forKey
- valueForKey