版本:iOS13.5
runtime.h
需要引入头文件#import
runtime其他方法通道
索引
- 返回对象obj的复制。(ARC模式下不可用)
object_copy
- 释放对象obj占用的内存。(ARC模式下不可用)
object_dispose
- 返回对象obj的类。
object_getClass
- 为对象obj设置新类。
object_setClass
- 检测对象obj是否为Class的对象。
object_isClass
- 读取对象obj中实例变量的值。
object_getIvar
- 设置对象obj中实例变量的值。
object_setIvar
- 设置对象obj中实例变量的值。(strong)
object_setIvarWithStrongDefault
- 更改对象obj的实例变量的值。(ARC模式下不可用)
object_setInstanceVariable
- 更改对象obj的实例变量的值。(ARC模式下不可用)(strong)
object_setInstanceVariableWithStrongDefault
- 获取实例变量的值。(ARC模式下不可用)
object_getInstanceVariable
- 通过名称获取类对象。(没注册时调用处理回调)
objc_getClass
- 通过名称获取元类对象。
objc_getMetaClass
- 通过名称获取类对象。(没注册时不调用处理回调)
objc_lookUpClass
- 通过名称获取类对象。(没注册时会崩溃)
objc_getRequiredClass
- 获取已注册类的数量。(含系统类、cocoPods类)
objc_getClassList
- 获取已注册类的指针数组。(含系统类、cocoPods类)
objc_copyClassList
详解
- 返回对象obj的复制。(ARC模式下不可用)
id _Nullable object_copy(id _Nullable obj, size_t size)
obj objc对象
size 对象的大小
- 释放对象obj占用的内存。(ARC模式下不可用)
id _Nullable object_dispose(id _Nullable obj)
- 返回对象obj的类。
Class _Nullable object_getClass(id _Nullable obj)
可以通过NSStringFromClass(class)
或class_getName
获取类的类名字符串
例子见object_isClass
- 为对象obj设置新类。
Class _Nullable object_setClass(id _Nullable obj, Class _Nonnull cls)
cls 要设置的新类
Class 返回原来的类
例子见object_isClass
- 检测对象obj是否为Class的对象。
BOOL object_isClass(id _Nullable obj)
例:
NSMutableArray *arr = [NSMutableArray array];
Class class = object_getClass(arr);
NSString *name = NSStringFromClass(class);
BOOL isClass = object_isClass(class);
BOOL isClass1 = object_isClass(name);
NSLog(@"%@ %@ %@", name, @(isClass), @(isClass1));
Class class1 = object_setClass(arr, [NSDictionary class]);
class = object_getClass(arr);
name = NSStringFromClass(class);
NSString *name1 = NSStringFromClass(class1);
NSLog(@"%@ %@", name, name1);
输出:object_setClass后arr变成了NSDictionary
__NSArrayM 1 0
NSDictionary __NSArrayM
- 读取对象obj中实例变量的值。
id _Nullable object_getIvar(id _Nullable obj, Ivar _Nonnull ivar)
如果实例变量的Ivar是已知的,则
object_getIvar
比object_getInstanceVariable
更快。
obj 包含该实例变量的对象
ivar 实例变量的Ivar描述 可通过runtime的class_getInstanceVariable
获取
例子见object_setIvarWithStrongDefault
- 设置对象obj中实例变量的值。
void object_setIvar(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value)
如果实例变量的Ivar是已知的,则
object_setIvar
比object_setInstanceVariable
更快。
变量如果具有已知内存管理(如ARC strong和weak)的实例变量则使用该内存管理。若为未知内存管理的实例变量则被分配为unsafe_unretained。
obj 包含该实例变量的对象
ivar 实例变量的Ivar描述 可通过runtime的class_getInstanceVariable
获取
value 实例变量的新值
例子见object_setIvarWithStrongDefault
- 设置对象obj中实例变量的值。(strong)
void
object_setIvarWithStrongDefault(id _Nullable obj, Ivar _Nonnull ivar, id _Nullable value)
如果实例变量的Ivar是已知的,则
object_setIvar
比object_setInstanceVariable
更快。
变量如果具有已知内存管理(如ARC strong和weak)的实例变量则使用该内存管理。若为未知内存管理的实例变量则被分配为strong。(和object_setIvar
的不同之处)
strong强引用 指向并拥有该对象,根据引用计数来管理内存,置为nil时计数减1,计数为0时释放内存。
weak弱引用 指向但并不拥有该对象,置为nil时只是让指针为空,对象并不会释放。
unsafe_unretain和weak类似,只是置为nil时不会将指针设置成nil,所以会有野指针的可能。
所以,在ARC下,object_setIvar
和object_setIvarWithStrongDefault
的作用几乎一样。
例:
self.title0 = @"runtime123";
Ivar ivar = class_getInstanceVariable(self.class, "_title0");
id name2 = object_getIvar(self, ivar);
NSLog(@"name2:%@", name2);
object_setIvar(self, ivar, @"runtime1234");
id name3 = object_getIvar(self, ivar);
NSLog(@"name3:%@", name3);
object_setIvarWithStrongDefault(self, ivar, @"runtime12345");
id name4 = object_getIvar(self, ivar);
NSLog(@"name4:%@", name4);
输出:
name2:runtime123
name3:runtime1234
name4:runtime12345
- 更改对象obj的实例变量的值。(ARC模式下不可用)
Ivar _Nullable object_setInstanceVariable(id _Nullable obj, const char * _Nonnull name,
void * _Nullable value)
obj 包含该实例变量的对象。
name 实例变量的名称
value 实例变量的新值void *
Ivar 返回实例变量的Ivar描述
- 更改对象obj的实例变量的值。(ARC模式下不可用)(strong)
Ivar _Nullable object_setInstanceVariableWithStrongDefault(id _Nullable obj,
const char * _Nonnull name, void * _Nullable value)
object_setInstanceVariableWithStrongDefault
和object_setInstanceVariable
的不同之处与object_setIvarWithStrongDefault
和object_setIvar
的不同之处一致。
- 获取实例变量的值。(ARC模式下不可用)
Ivar _Nullable object_getInstanceVariable(id _Nullable obj, const char * _Nonnull name,
void * _Nullable * _Nullable outValue)
obj 包含该实例变量的对象。
name 实例变量的名称
outValue void **指针,保存实例变量的值。
Ivar 返回实例变量的Ivar描述
- 通过名称获取类对象。(没注册时调用处理回调)
Class _Nullable objc_getClass(const char * _Nonnull name)
objc_getClass
与objc_lookUpClass
的不同之处在于,如果未注册该类,objc_getClass
会调用类处理程序回调,然后再次检查该类是否已注册。而objc_lookUpClass
则不调用类处理程序回调。
name 类的名称
例子见objc_getMetaClass
- 通过名称获取元类对象。
Class _Nullable objc_getMetaClass(const char * _Nonnull name)
元类 类所属的类(见例子) 弄懂OC中的类与元类
如果未注册该类,则此函数将调用类处理程序回调,然后再次检查该类是否已注册。但是,每个类定义都必须具有有效的元类,因此无论是否有效,总能返回元类。
name 类的名称
例:
{
NSArray *array = @[];
//获取array的类
Class class = object_getClass(array);
//获取array的元类
Class metaClass = object_getClass(class);
}
Class class2 = objc_getClass("NSArray");
BOOL isCalss2 = object_isClass(class2);
NSLog(@"%@ %@", @(isCalss2), class2);
Class class3 = objc_getMetaClass("NSArray");
BOOL isCalss3 = object_isClass(class3);
NSLog(@"%@ %@", @(isCalss3), class3);
输出:
1 NSArray
1 NSArray
- 通过名称获取类对象。(没注册时不调用处理回调)
Class _Nullable objc_lookUpClass(const char * _Nonnull name)
objc_getClass
与objc_lookUpClass
的不同之处在于,如果未注册该类,objc_getClass
会调用类处理程序回调,然后再次检查该类是否已注册。而objc_lookUpClass
则不调用类处理程序回调。
name 类的名称
例子见objc_getRequiredClass
- 通过名称获取类对象。(没注册时会崩溃)
Class _Nonnull objc_getRequiredClass(const char * _Nonnull name)
objc_getRequiredClass
与objc_getClass
相同,但是如果找不到该类,则会崩溃。
例:
Class class4 = objc_getMetaClass("NSArray");
BOOL isCalss4 = object_isClass(class4);
NSLog(@"%@ %@", @(isCalss4), class4);
Class class5 = objc_getRequiredClass("NSArray1");
BOOL isCalss5 = object_isClass(class5);
NSLog(@"%@ %@", @(isCalss5), class5);
输出:会在objc_getRequiredClass处崩溃
1 NSArray
objc[34190]: link error: class 'NSArray1' not found.
- 获取已注册类的数量。(含系统类、cocoPods类)
int objc_getClassList(Class _Nonnull * _Nullable buffer, int bufferCount)
Objective-C运行时库会自动注册源代码中所有类。您可以在运行时使用
objc_addClass
进行注册。
buffer 类的指针数组。可以传递NULL来获取已注册类的总数,而不用实际检索任何类。
bufferCount 要获取类的数量 bufferCount与已注册类总数以较小者为准 传0时为表示获取已注册类总数的类值 小于0时表示不取任何值
int 返回已注册类的总数
例:
//获取已注册类的数量
int classCount = objc_getClassList(NULL, 0);
NSLog(@"total = %d", classCount);
//为类的指针数组分配内存
Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * classCount);
///获取前10个类
objc_getClassList(classes, 10);
NSMutableArray *resultArray = [NSMutableArray array];
//创建信号 为1时可以保证数据线程安全
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
//加锁
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
Class class = classes[index];
[resultArray addObject:NSStringFromClass(class)];
//解锁
dispatch_semaphore_signal(semaphore);
});
NSLog(@"%@", resultArray);
///释放内存
free(classes);
输出:
total = 20577
(
JSExport,
NSLeafProxy,
NSProxy,
"_UIActivityPlaceholderItemProxy",
"_UITargetedProxy",
"_UIViewServiceUIBehaviorProxy",
"_UIViewServiceReplyControlTrampoline",
"_UIViewServiceReplyAwaitingTrampoline",
"_UIViewServiceImplicitAnimationDecodingProxy",
"_UIViewServiceImplicitAnimationEncodingProxy"
)
- 获取已注册类的指针数组。(含系统类、cocoPods类)
Class _Nonnull * _Nullable objc_copyClassList(unsigned int * _Nullable outCount)
必须使用
free
将返回值Class *
释放
outCount 指针 保存已注册类的总数
例:
unsigned int classCount;
Class *classes = objc_copyClassList(&classCount);
NSLog(@"total = %d", classCount);
NSMutableArray *resultArray = [NSMutableArray array];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_apply(10, dispatch_get_global_queue(0, 0), ^(size_t index) {
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
Class class = classes[index];
[resultArray addObject:NSStringFromClass(class)];
dispatch_semaphore_signal(semaphore);
});
NSLog(@"%@", resultArray);
free(classes);
输出:
total = 20577
(
JSExport,
NSLeafProxy,
NSProxy,
"_UIActivityPlaceholderItemProxy",
"_UITargetedProxy",
"_UIViewServiceUIBehaviorProxy",
"_UIViewServiceReplyControlTrampoline",
"_UIViewServiceReplyAwaitingTrampoline",
"_UIViewServiceImplicitAnimationDecodingProxy",
"_UIViewServiceImplicitAnimationEncodingProxy"
)