Objective-C的本质
Objective-C -> C/C++ -> 汇编语言 ->机器语言
Objective-C 简单转换 C\C++代码(代码比较多)
clang -rewrite-objc main.m -o main.cpp
转换成对应平台下cpp文件
模拟器(i386, x86-64) 32bit(armv7) 64bit(arm64)
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
Objective-C的面向对象都是基于C\C++实现的,本质是结构体.
@interface NSObject <NSObject> {
Class isa;
}
struct NSObject_IMPL {
Class isa;
};
typedef struct objc_class *Class;
至少需要多少内存(计算结构体内存大小)
class_getInstanceSize([NSObject class]) // 8
实际分配内存大小(操作系统内存对齐)
malloc_size((__bridge const void *)([[NSObject alloc] init])) // 16
指针变量obj占用多少内存空间
NSObject *obj = [[NSObject alloc] init];
sizeof(obj); //8
Objective-C的分类
instance对象(实例对象)
obj是NSObject的instance对象(实例对象)
NSObject *obj = [[NSObject alloc] init];
instance对象在内存中存储信息主要包括
isa指针
其他成员变量
......
class对象(类对象)
objClass1,objClass2,objClass3是同一个对象,每个类有且只有一个类对象
Class objClass1 = [obj class];
Class objClass2 = [NSObject class];
Class objClass3 = object_getClass(obj);
class对象在内存中存储信息主要包括
isa指针
superClass指针
类的属性(@property),类的对象方法(instance method)
类的协议(protocol),类的成员变量(ivar)
......
meta-class对象(元类对象)
objMetaClass是NSObject的元类对象,每个类有且只有一个元类对象
Class objMetaClass = object_getClass([NSObject class]);
是否是元类对象
BOOL isMeta = class_isMetaClass(objMetaClass);
元类对象是特殊的类对象
meta-class对象在内存中存储信息主要包括
isa指针
superClass指针
类的类方法(class method)
......
isa指针和superClass指针
instance对象 isa -> class对象 -> meta-class对象 -> 基类的meta-class对象
class的superClass -> 父类的class(若是空,superClass是nil)
meta-class的superClass -> 父类的meta-class
基类的meta-class的superClass -> 基类的class
instance调用对象方法路径: isa找到class,若不存在,通过superClass找父类
class调用类方法路径:isa找meta-class,若不存在,通过superClass找父类
isa指针
从64位开始优化,需要&ISA_MASK
instance的 isa & ISA_MASK 得到 class的isa
class的 isa & ISA_MASK 得到 meta-class 的isa
objc4源码查看 https://opensource.apple.com/tarballs/objc4/
typedef struct objc_class *Class;
struct objc_class {
Class isa;
Class superClass;
cache_t cache; //方法缓存
class_data_bits_t bits; //用于获取具体的类信息
......
};
bits & FAST_DATA_MASK 得到 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;
......
};
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;
}
};
KVO的全称是Key-Value Observing,俗称“键值监听”,可以用于监听某个对象属性值的改变
KVO代码层面使用
//添加监听属性
- (void)addKVOTest {
self.kvo = [[KVOTest alloc] init];
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.kvo addObserver:self forKeyPath:@"age" options:options context:@"123"];
}
//合适时机销毁
- (void)dealloc {
[self.kvo removeObserver:self forKeyPath:@"age"];
}
//监听属性的变化
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)context {
NSLog(@"监听到%@的%@属性值改变了 - %@ - %@", object, keyPath, change, context);
}
KVO底层原理:
使用KVO监听后,runtime会动态创建一个 NSKVONotifying_监听类,是监听类的子类
调用方法顺序
willChangeValueForKey:
setAge: ( Foundation下_NSSetIntValueAndNotify() )
observerValueForKey
didChangeValueForKey:
KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKey:(NSString *)key;
- (id)valueForKeyPath:(NSString *)keyPath;
- (id)valueForKey:(NSString *)key;
setValueForKey的流程
1、按照setKey、_setKey顺序查找方法, 找到了直接调用方法
2、如果找不到,查看accessInstanceVariablesDirectly(能否直接访问成员变量)的返回值,
NO,直接报错 setValue:forUndefinedKey:,
YES,通过_key, _isKey, key, isKey顺序查找成员变量,找到了直接赋值,都找不到直接报错 setValue:forUndefinedKey:
valueForKey的流程
1、按照getKey、Key、isKey、_key的顺序查找方法,找到直接调用
2、如果找不到,查看accessInstanceVariablesDirectly(能否直接访问成员变量)的返回值,
NO,直接报错 setValue:forUndefinedKey:,
YES,通过_key, _isKey, key, isKey顺序查找成员变量,找到了直接取值,都找不到直接报错 setValue:forUndefinedKey:
Category
分类的底层结构
终端输入
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc NSObject+FenLeiTest.m
struct _category_t {
const char *name;
struct _class_t *cls;
const struct _method_list_t *instance_methods;
const struct _method_list_t *class_methods;
const struct _protocol_list_t *protocols;
const struct _prop_list_t *properties;
};
1、通过Runtime加载某个类的所有Category数据
2、把所有Category的方法、属性、协议数据,合并到一个大数组中
后面参与编译的Category数据,会在数组的前面
3、将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面