接着第一篇介绍了Objective-C中的重要概念的内存模型,这一篇就来熟悉对内存模型的读写操作。
Class操作
Class的操作就是围绕Class的内存模型进行的读写操作,参考上一篇内存模型。
1,获取类名字符串
const char * class_getName ( Class cls );
nil是一个对象值,如果要把一个对象设置为空的时候就用nil。Nil是一个类对象的值,如果要把一个Class类型的对象设置为空的时候就用Nil。NULL是一个通用指针。
本质nil,Nil,NULL和NSNull的值一样的,都表示空数据。 nil,Nil,NULL 指针指向的内容是一样的,都是0x00。NSNull是一个对象,表示空对象。
2,获取Class的父类
Class class_getSuperclass ( Class cls ); //NSObject的superClass是nil;
3,判断一个类是否是一个元类
BOOL class_isMetaClass ( Class cls );//NSObject及其子类的metaClass的metaClass都指向NSObject的metaClass,NSObject的metaClass的superClass指向NSObject,而NSObject的superClass是Nil。
4,获取类的实例的内存size。
size_t class_getInstanceSize ( Class cls );//MBP上,demo类没有任何属性时size为8,添加一个属性size增加8;
5,成员变量操作
Class中的成员变量是用数组存储的。好处是读写快。
struct objc_ivar_list *ivars;
5.1 获取一个成员变量IVar , 会向父类查询。
Ivar class_getInstanceVariable ( Class cls, const char *name );
5.2 获取类成员变量的信息
Ivar class_getClassVariable ( Class cls, const char *name );
5.3 增加一个成员变量,只用于动态生成的类,已有的类不能通过这个方式增加成员变量。需要注意的是,这个方法只能在objc_allocateClassPair函数与objc_registerClassPair之间调用。成员变量的按字节最小对齐量是1<<alignment,如果变量的类型是指针类型,则传递log2(sizeof(pointer_type));
BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
eg.
BOOL isC = class_addIvar(TestVar,"name6",sizeof(NSString*),log2(sizeof(NSString*)),@encode(NSString*)); //recommend.
BOOL isC = class_addIvar(TestVar,"name7",sizeof(NSString*),log2(_Alignof(NSString*)),@encode(NSString*));//
5.4 获取当前Class的成员变量列表,不包含父类的。
Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
6 属性操作
属性和成员变量的操作是分开的,但是属性和成员变量存储在同一块数组里面,就是Class里面的struct objc_ivar_list * ivars。
6.1 获取指定属性,会向父类查询。
objc_property_t class_getProperty ( Class cls, const char *name );
6.2 获取属性列表
objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
6.3 给类添加属性。属性添加依然要放在动态生成的类中,参考添加变量的方法。5.3
BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
6.4 替换类的属性
void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
7 方法操作
在Class的内存模型里面,方法列表存储在一个链表中,这是因为runtime支持在运行时为已有类和动态生成的类,添加方法,用链表而不用数组来存储,很好地满足这个需求。
7.1 给类添加一个方法。
BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
给meta class添加的是类方法,给普通类添加的是实例方法。
往metaClass里面增加的Method,既可以通过class_getInstanceMethod取到,也可以通过class_getClassMethod取到,但是调用只能是类对象Class对象能调用。这个情况,在非metaClass里面不行,非metaClass里面instanceMethod和classMethod互补侵犯。
7.2 获取所有方法的数组
Method * class_copyMethodList ( Class cls, unsigned int *outCount );//对于非metaClass而言,这里不包含类方法,类方法在metaClass里面。
7.3 获取实例方法。
Method class_getInstanceMethod ( Class cls, SEL name ); //注意runtime官方是通过selector来定位一个方法,而不是方法名。前面说过,方法名和selector之间有对应关系。
7.4 获取类方法
Method class_getClassMethod ( Class cls, SEL name );
7.5 替换方法的具体实现
IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
注意点:如果已经有这个SEL,那么就更新这个SEL的IMP,如果没有这个SEL,那么相当于class_addMethod..
7.6 获取一个方法的具体实现
IMP class_getMethodImplementation ( Class cls, SEL name );//注意:非metaClass里面,类方法获取不到。这个方法会搜索父类。
如果找到了,返回的IMP的描述如下:
Printing description of imp1:
(IMP) imp1 = 0x0000000100001940 (MyCommandLineDemo`-[MethodOperationSuper methodOperationSuperTest] at MethodOperationSuper.m:13)
如果找不到,会返回消息转发的IMP
Printing description of imp1:
(IMP) imp1 = 0x00007fffdc31dcc0 (libobjc.A.dylib`_objc_msgForward)
7.7 判断一个Class是否能够响应一个selector
BOOL class_respondsToSelector ( Class cls, SEL sel );//注意,这个方法会搜索父类,非metaClass找不到类方法。
8 协议操作
8.1 给类增加一个协议。
BOOL class_addProtocol ( Class cls, Protocol *protocol );
8.2 检查一个类是否遵守了一个协议
BOOL class_conformsToProtocol ( Class cls, Protocol *protocol );
8.3 返回类实现的协议列表
Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );//注意,该方法不去查询父类遵守的协议。
9.动态创建类
runtime可以在运行期间,动态创建一个类。需要以下流程:
//1.创建一个类,指定父类,类名。
Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes );//extraBytes这个字段一般不需要,设为0;
//2.往类里面填东西,变量,方法。
class_addIvar..
class_addProperty..
class_addMethod..
//3.注册创建好的类。
void objc_registerClassPair ( Class cls );
//4.也可以动态的销毁一个类。
void objc_disposeClassPair ( Class cls );//需要注意的是,如果程序运行中还存在类或其子类的实例,则不能调用针对类调用该方法
9.动态创建类
1.获取注册类列表的数量
int objc_getClassList ( Class *buffer, int bufferCount );//buffer是一个类指针。
//eg.
int numClasses;
Class * classes = NULL;
numClasses = objc_getClassList(NULL, 0);
if (numClasses > 0) {
classes = malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
NSLog(@"number of classes: %d", numClasses);
for (int i = 0; i < numClasses; i++) {
Class cls = classes[i];
NSLog(@"class name: %s", class_getName(cls));
}
free(classes);
}
2.获取注册类列表的指针
Class * objc_copyClassList ( unsigned int *outCount );