[Cocoa]深入浅出Cocoa 之动态创建类

深入浅出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,我们可以在之后使用
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;
}

在上面的代码中,我们创建继承自 NSString 的子类 NSStringSubclass ,然后向其中添加方法 report,并在运行时系统中注册,这样我们就可以使用这个新类了。在这里使用 performSelector 来向新类的对象发送消息,可以避免编译警告信息(因为我们并没有声明该类及其可响应的消息)。

执行结果为:
>>This object is0x100114710.
>>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 是其自身


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值