Runtime简介
RunTime简称运行时。OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制。
对于C语言,函数的调用在编译的时候会决定调用哪个函数。
对于OC语言,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用。事实证明:1、在编译阶段,OC可以调用任何函数,即使用这个函数并未实现,只要声明过就不会报错。2、在编码阶段,C语言调用未实现的函数就会报错。
一、获取类的名称
1、通过类获取类的名称
OBJC_EXPORT const char * _Nonnull
class_getName(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
参数:通过传入Class类型的cls来获的class的名字
例:
//获取类名
const char *className=class_getName([Dog class]);
NSLog(@"%s",className);// Dog
2、通过对象获取类的名称
OBJC_EXPORT const char * _Nonnull object_getClassName(id _Nullable obj)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
例:
Dog *dog=[[Dog alloc]init];
const char *className=object_getClassName(dog);
NSLog(@"%s",className);//Dog
二、通过名称或对象获取类
1、
OBJC_EXPORT Class _Nullable
objc_getClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
2、
OBJC_EXPORT Class _Nullable
objc_lookUpClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
3、
OBJC_EXPORT Class _Nonnull
objc_getRequiredClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
4、
OBJC_EXPORT Class _Nullable
object_getClass(id _Nullable obj)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
以上为获取类的四种方法:
objc_getClass objc_lookUpClass 返回当前类,当你找的类不存在,返回nil;
objc_getRequiredClass 返回当前类,当你要找的类不存在的话会闪退,慎用。
object_getClass 通过对象返回当前类
例:
Dog *dog=[[Dog alloc]init];
// 1、通过c对象获取类
Class objectGetClaas= object_getClass(dog);
NSLog(@"%@",objectGetClaas);//Dog
const char *className="Dog"; //当前类名存在
const char *className1="Dog1";//当前类名不存在
Class getClass=objc_getClass(className);
NSLog(@"%@",getClass);//Dog
Class getClass1=objc_getClass(className1);
NSLog(@"%@",getClass1);//(null)
Class lookUpClass=objc_lookUpClass(className);
NSLog(@"%@",lookUpClass);//Dog
Class lookUpClass1=objc_lookUpClass(className1);
NSLog(@"%@",lookUpClass1);//(null)
Class getRequiredClass=objc_getRequiredClass(className);
NSLog(@"%@",getRequiredClass);//Dog
Class getRequiredClass1=objc_getRequiredClass(className1);
NSLog(@"%@",getRequiredClass1);//闪退 报错 link error: class 'Dog1' not found.
* objc_getClass(const char * _Nonnull name) 与object_getClass(id _Nullable obj) 区别:
1、objc_getClass(const char * _Nonnull name) 传入字符串类名 返回对应的类对象
2、object_getClass(id _Nullable obj)
a:传入obj可能是instance 对象返回的是 class对象
b:传入是class对象,返回meta-class对象
c:传入meta-class对象,返回NSObject(基类)的meta-class对象
三、元类对象
Class不仅可以代表类对象,还可以代表元类对象。
1、获取元类对象
OBJC_EXPORT Class _Nullable
objc_getMetaClass(const char * _Nonnull name)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
例:
const char *className="Dog";
Class metaClass=objc_getMetaClass(className);
NSLog(@"%@",metaClass);//Dog
2、判断是否是元类对象
OBJC_EXPORT BOOL
class_isMetaClass(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
例:
const char *className="Dog";
Class metaClass=objc_getMetaClass(className);
Class class1=objc_getClass(className);
BOOL isMetaClass1=class_isMetaClass(metaClass);
BOOL isMetaClass2=class_isMetaClass(class1);
NSLog(@"%d %d",isMetaClass1,isMetaClass2); // 1 0
3、判断 类(元类)对象和实例对象
objc_getClass 生成类类对象 ; class_isMetaClass 生成元类对象
OBJC_EXPORT BOOL
object_isClass(id _Nullable obj)
OBJC_AVAILABLE(10.10, 8.0, 9.0, 1.0, 2.0);
只要是类对象或者元类对象都会返回YES
例:
const char *className="Dog";
//类对象
Class getClass=objc_getClass(className);
//元类对象
Class metaClass=objc_getMetaClass(className);
//对象
Dog *dog=[[Dog alloc]init];
//只要是类对象或元类对象返回yes
NSLog(@"%d",object_isClass(getClass)); //返回 1 是类对象
NSLog(@"%d",object_isClass(metaClass)); //返回 1 是元类对象
NSLog(@"%d",object_isClass(dog)); // 返回 0 实例对象
4、获取父类对象
OBJC_EXPORT Class _Nullable
class_getSuperclass(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
例:
const char *className="Dog";
//类对象
Class getClass=objc_getClass(className);
Class getClassName=class_getSuperclass(object_getClass(getClass));
NSLog(@"%@",getClassName); //NSObject
5、runtime里面的强转类型
OBJC_EXPORT Class _Nullable
object_setClass(id _Nullable obj, Class _Nonnull cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
例:
Dog *dog=[[Dog alloc]init];
Class oldClass=object_setClass(dog, objc_getClass("NSObject"));
NSLog(@"%@",oldClass);//Dog
NSLog(@"%@",[dog class]);//NSObject
四、动态新增类
1、创建一个新类:
参数 : superclass :是新类所继承的类,如果为nil. superclass为根类,NSObject
name:是新类的名字。
extraBytes:是在类和元类对象的末尾为索引ivars分配的字节数。这一般是0,
OBJC_EXPORT Class _Nullable
objc_allocateClassPair(Class _Nullable superclass, const char * _Nonnull name,
size_t extraBytes)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
2、注册类:
如果一个类通过 objc_allocateClassPair 创建,必须注册之后才能使用:objc_registerClassPair
OBJC_EXPORT void
objc_registerClassPair(Class _Nonnull cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
3、此方法在系统KVO的底层用过,系统不推荐我们自己使用。
OBJC_EXPORT Class _Nonnull
objc_duplicateClass(Class _Nonnull original, const char * _Nonnull name,
size_t extraBytes)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
4、销毁
bjc_disposeClassPair只能销毁通过objc_allocateClassPair创建的类。
OBJC_EXPORT void
objc_disposeClassPair(Class _Nonnull cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
例:
const char * className="Cat";
// 1、创建类
Class cat=objc_allocateClassPair(objc_getClass("NSObject"), className, 0);
NSLog(@"%@",objc_getClass(className));//(null)
//2、注册类
objc_registerClassPair(cat);
NSLog(@"%@",objc_getClass(className));//Cat
//3、销毁类
objc_disposeClassPair(cat);
NSLog(@"%@",objc_getClass(className));//(null)
五、获取注册类的方法
1、获取所有注册类的列表方式一:
OBJC_EXPORT Class _Nonnull * _Nullable
objc_copyClassList(unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.7, 3.1, 9.0, 1.0, 2.0);
例:
unsigned int outCount;
Class *classs=objc_copyClassList(&outCount);
NSLog(@"总个数;%d",outCount);//总个数;15767
for (int i=0; i<outCount; i++) {
NSLog(@"%s",object_getClassName(classs[i]));
}
free(classs);
2、获取所有注册类的列表方式二:
OBJC_EXPORT int
objc_getClassList(Class _Nonnull * _Nullable buffer, int bufferCount)
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
第一个参数buffer
已分配好内存空间的数组指针,bufferCount
是数组的个数,如果bufferCount
的数量小于实际的数组数量,那么buffer
返回的是所有数组集合的任意一个子类。如果buffer
为NULL,那么bufferCount
为0。无论那种情况,返回结果都是当前注册类的总数。
例:
int bufferCount= 4;
Class *buffer=(Class*)malloc(sizeof(Class)*bufferCount);
int count1=objc_getClassList(buffer, bufferCount);
for (int i=0; i<bufferCount; i++) {
NSLog(@"name=%s",class_getName(buffer[i]));
}
NSLog(@"count1=%d",count1);
int count2=objc_getClassList(NULL, 0);
NSLog(@"count2=%d",count2);
六、类实例的大小
1、一个没有变量或属性的继承于NSObject的类占有8个字节
OBJC_EXPORT size_t
class_getInstanceSize(Class _Nullable cls)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
例:
size_t size =class_getInstanceSize(objc_getClass("Dog"));
NSLog(@"%zu",size);
2、创建实例的方法
OBJC_EXPORT id _Nullable
class_createInstance(Class _Nullable cls, size_t extraBytes)
OBJC_RETURNS_RETAINED
OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
cls
是要创建的类,extraBytes
是额外的字节内存,用来存储类定义中的实例变量之外的其他实例变量
例:
//OC创建对象
Persion *p=[[Persion alloc]init];
p.name=@"哈哈";
NSLog(@"%@",p.name);//哈哈
//runtime
Persion *p1=class_createInstance(objc_getClass("Persion"), 0);
p1.name=@"嘿嘿";
NSLog(@"%@",p1.name);//嘿嘿