深入浅出Cocoa 之动态创建类
CC许可,转载请注明出处
在前文 《深入浅出Cocoa之类与对象》 一文中,我已经详细介绍了ObjC中的 Class 与 Object 的概念,今天我们来如何在运行
时
动态创建类。下面这个函数就是应用前面讲到的Class,MetaClass的概念,在运行时动态创建一个类。这个函数来自《Inside Mac OS X-The Objective-C Programming Language》。
#import<objc/objc.h>
#import<objc/runtime.h>
BOOLCreateClassDefinition( const char*name, const char*superclassName)
{
structobjc_class*meta_class;
structobjc_class*super_class;
structobjc_class*new_class;
structobjc_class*root_class;
va_listargs;
// 确保父类存在
super_class=( structobjc_class*)objc_lookUpClass(superclassName);
if(super_class==nil)
{
returnNO;
}
// 确保要创建的类不存在
if(objc_lookUpClass(name)!=nil)
{
returnNO;
}
// 查找 root class,因为 meta class 的 isa 指向 root class 的 meta class
root_class=super_class;
while(root_class->super_class!=nil)
{
root_class=root_class->super_class;
}
// 为class及其metaclass 分配内存
new_class=calloc(2, sizeof( structobjc_class));
meta_class=&new_class[1];
// 设置class
new_class->isa=meta_class;
new_class->info=CLS_CLASS;
meta_class->info=CLS_META;
// 拷贝类名字,这里为了提高效率,让 class 与 meta class 都指向同一个类名字符串
new_class->name=malloc(strlen(name)+1);
strcpy(( char*)new_class->name,name);
meta_class->name=new_class->name;
// 分配并置空 methodlists,我们可以在之后使用
new_class->methodLists=calloc(1, sizeof( structobjc_method_list*));
meta_class->methodLists=calloc(1, sizeof( structobjc_method_list*));
// 将类加入到继承体系中去:
// 1,设置类的 super class
// 2,设置 meta class 的 super class
// 3,设置 meta class 的 isa
new_class->super_class = super_class;
meta_class->super_class=super_class->isa;
meta_class->isa=( void*)root_class->isa;
// 最后,将 class 注册到运行时系统中
objc_addClass(new_class);
returnYES;
}
#import<objc/runtime.h>
BOOLCreateClassDefinition( const char*name, const char*superclassName)
{
structobjc_class*meta_class;
structobjc_class*super_class;
structobjc_class*new_class;
structobjc_class*root_class;
va_listargs;
// 确保父类存在
super_class=( structobjc_class*)objc_lookUpClass(superclassName);
if(super_class==nil)
{
returnNO;
}
// 确保要创建的类不存在
if(objc_lookUpClass(name)!=nil)
{
returnNO;
}
// 查找 root class,因为 meta class 的 isa 指向 root class 的 meta class
root_class=super_class;
while(root_class->super_class!=nil)
{
root_class=root_class->super_class;
}
// 为class及其metaclass 分配内存
new_class=calloc(2, sizeof( structobjc_class));
meta_class=&new_class[1];
// 设置class
new_class->isa=meta_class;
new_class->info=CLS_CLASS;
meta_class->info=CLS_META;
// 拷贝类名字,这里为了提高效率,让 class 与 meta class 都指向同一个类名字符串
new_class->name=malloc(strlen(name)+1);
strcpy(( char*)new_class->name,name);
meta_class->name=new_class->name;
// 分配并置空 methodlists,我们可以在之后使用
class_addMethods 向类中增加方法
new_class->methodLists=calloc(1, sizeof( structobjc_method_list*));
meta_class->methodLists=calloc(1, sizeof( structobjc_method_list*));
// 将类加入到继承体系中去:
// 1,设置类的 super class
// 2,设置 meta class 的 super class
// 3,设置 meta class 的 isa
new_class->super_class = super_class;
meta_class->super_class=super_class->isa;
meta_class->isa=( void*)root_class->isa;
// 最后,将 class 注册到运行时系统中
objc_addClass(new_class);
returnYES;
}
如果要在代码中使用运行时相关的函数,我们需要导入 libobjc.dylib,并导入相关的头文件(比如这里的 runtime.h)。
在 前文 中总结到“ ObjC 为每个类的定义生成两个 objc_class ,一个即普通的 class,另一个即 metaclass。我们可以在运行期创建这两个 objc_class 数据结构,然后使用 objc_addClass 动态地创建新的类定义。 ”,这在上面的代码中就体现出来了:new_class 和 meta_class 就是新类所必须的两个 objc_class。其他的代码就不解释了,注释以及代码足以自明了。
在实际的运用中,我们使用 ObjC 运行时函数来动态创建类:
Classobjc_allocateClassPair(Classsuperclass,
const
char*name,size_textraBytes);
譬如:
#import<objc/objc.h>
#import<objc/runtime.h>
voidReportFunction(idself,SEL_cmd)
{
NSLog(@">>Thisobjectis%p.",self);
NSLog(@">>Classis%@,andsuperis%@.",[self class],[selfsuperclass]);
ClassprevClass=NULL;
intcount=1;
for(ClasscurrentClass=[self class];currentClass;++count)
{
prevClass=currentClass;
NSLog(@">>Followingtheisapointer%dtimesgives%p",count,currentClass);
currentClass=object_getClass(currentClass);
if(prevClass==currentClass)
break;
}
NSLog(@">>NSObject'sclassis%p",[NSObject class]);
NSLog(@">>NSObject'smetaclassis%p",object_getClass([NSObject class]));
}
intmain( intargc, const char*argv[])
{
@autoreleasepool
{
ClassnewClass=objc_allocateClassPair([NSString class],"NSStringSubclass",0);
class_addMethod(newClass,@selector(report),(IMP)ReportFunction,"v@:");
objc_registerClassPair(newClass);
idinstanceOfNewClass=[[newClassalloc]init];
[instanceOfNewClassperformSelector:@selector(report)];
[instanceOfNewClassrelease];
}
return0;
}
#import<objc/runtime.h>
voidReportFunction(idself,SEL_cmd)
{
NSLog(@">>Thisobjectis%p.",self);
NSLog(@">>Classis%@,andsuperis%@.",[self class],[selfsuperclass]);
ClassprevClass=NULL;
intcount=1;
for(ClasscurrentClass=[self class];currentClass;++count)
{
prevClass=currentClass;
NSLog(@">>Followingtheisapointer%dtimesgives%p",count,currentClass);
currentClass=object_getClass(currentClass);
if(prevClass==currentClass)
break;
}
NSLog(@">>NSObject'sclassis%p",[NSObject class]);
NSLog(@">>NSObject'smetaclassis%p",object_getClass([NSObject class]));
}
intmain( intargc, const char*argv[])
{
@autoreleasepool
{
ClassnewClass=objc_allocateClassPair([NSString class],"NSStringSubclass",0);
class_addMethod(newClass,@selector(report),(IMP)ReportFunction,"v@:");
objc_registerClassPair(newClass);
idinstanceOfNewClass=[[newClassalloc]init];
[instanceOfNewClassperformSelector:@selector(report)];
[instanceOfNewClassrelease];
}
return0;
}
在上面的代码中,我们创建继承自 NSString 的子类 NSStringSubclass ,然后向其中添加方法 report,并在运行时系统中注册,这样我们就可以使用这个新类了。在这里使用 performSelector 来向新类的对象发送消息,可以避免编译警告信息(因为我们并没有声明该类及其可响应的消息)。
执行结果为:
>>This
object
is0x100114710.
>>Class isNSStringSubclass,andsuper isNSString.
>>Followingtheisapointer1timesgives0x100114410
>>Followingtheisapointer2timesgives0x100114560
>>Followingtheisapointer3timesgives0x7fff7e257b50
>>NSObject'sclassis0x7fff7e257b78
>>NSObject'smetaclassis0x7fff7e257b50
>>Class isNSStringSubclass,andsuper isNSString.
>>Followingtheisapointer1timesgives0x100114410
>>Followingtheisapointer2timesgives0x100114560
>>Followingtheisapointer3timesgives0x7fff7e257b50
>>NSObject'sclassis0x7fff7e257b78
>>NSObject'smetaclassis0x7fff7e257b50
根据前文中的类关系图,我们不难从执行结果中分析出 NSStringSubclass 的内部类结构:
1,对象的地址为 : 0x100114710
2,class 的地址为: 0x100114410
3,meta class 的地址为: 0x100114560
4,meta class 的 class 地址为: 0x7fff7e257b50 (也是 NSObject 的 meta class)
5,NSObject 的 meta class 的meta class 是其自身