是否可以在objective-c中运行时定义类? 例如。我收到一个XML文件,它定义一个对象并创建它并在运行时使用它?
答案 0 :(得分:6)
是的,请检查此代码段,我在这里创建了一个类,仅使用C方法和一个协议定义(为了简化消息调用)...
MyCObject.h
#import <Foundation/Foundation.h>
@protocol MyCObj_methods<NSObject>
-(NSString *) getString;
-(int) getInt;
+(NSString *) someStaticMethod;
@end
typedef id<MyCObj_methods> MyCObj;
extern Class MyCObj_class;
__attribute__((constructor))
void MyCObj_initialize();
MyCObj MyCObj_alloc( id self, SEL _cmd );
MyCObj MyCObj_new( id self, SEL _cmd );
NSString *MyCObj_someStaticMethod ( id self, SEL _cmd );
MyCObj MyCObj_init( MyCObj self, SEL _cmd );
NSString *MyCObj_getString( MyCObj self, SEL _cmd );
int MyCObj_getInt( MyCObj self, SEL _cmd );
MyCObject.m
#import "MyCObject.h"
#import <objc/Object.h>
#import <objc/runtime.h>
static Class myStaticClass;
Class MyCObj_class;
typedef struct
{
Class isa;
NSString *myString;
int myInt;
} MyCObj_t;
void MyCObj_initialize(void);
__attribute__((constructor))
void MyCObj_initialize()
{
MyCObj_class = objc_allocateClassPair([NSObject class], "MyCObj", 0);
objc_registerClassPair(MyCObj_class);
myStaticClass = object_getClass(MyCObj_class);
class_addMethod(MyCObj_class, @selector(init), (IMP)MyCObj_init, "@@:");
class_addMethod(MyCObj_class, @selector(getString), (IMP)MyCObj_getString, "@@:");
class_addMethod(MyCObj_class, @selector(getInt), (IMP)MyCObj_getInt, "i@:");
class_addMethod(myStaticClass, @selector(alloc), (IMP)MyCObj_alloc, "@@:");
class_addMethod(myStaticClass, @selector(new), (IMP)MyCObj_new, "@@:");
class_addMethod(myStaticClass, @selector(someStaticMethod), (IMP)MyCObj_someStaticMethod, "@@:");
}
MyCObj MyCObj_alloc(id self, SEL _cmd)
{
return (MyCObj) class_createInstance(MyCObj_class, sizeof(MyCObj_t) - sizeof(Class));
}
MyCObj MyCObj_new(id self, SEL _cmd)
{
return (MyCObj) [[MyCObj_class alloc] init];
}
NSString *MyCObj_someStaticMethod(id self, SEL _cmd)
{
return @"Some Static Method";
}
MyCObj MyCObj_init(MyCObj self, SEL _cmd)
{
struct objc_super super = { .receiver = self, .super_class = [NSObject class] };
if ((self = (MyCObj) objc_msgSendSuper(&super, _cmd)))
{
((MyCObj_t *) self)->myString = @"hello world!";
((MyCObj_t *) self)->myInt = 15;
}
return self;
}
NSString *MyCObj_getString(MyCObj self, SEL _cmd)
{
return ((MyCObj_t *) self)->myString;
}
int MyCObj_getInt(MyCObj self, SEL _cmd)
{
return ((MyCObj_t *) self)->myInt;
}
用法:
MyCObj obj = [MyCObj_class new];
NSLog(@"%@ %i %@", [obj getString], [obj getInt], [MyCObj_class someStaticMethod]);
答案 1 :(得分:5)
是;完全有可能。有关详细信息,请参阅Objective-C Runtime Programming Guide(包括相关指南和文档)。
正如贾斯汀所说,走这条路是非常不典型的。如果要加载XML数据,那么几乎总是强制转换说XML必须具有良好定义的结构 - 严格的DTD或模式 - 因此,使用规范,定义明确的数据模型会更好编译到您的应用程序(通过核心数据或直接实现),您加载XML。这样可以实现更严格的验证,并且会更加容易。
“自由形式数据消费”的圣杯是诱人的,但沿着这条道路走下去的是疯狂和许多悲惨的故事。
答案 2 :(得分:2)
是的,你可以使用objc运行时来创建一个类型,定义方法及其存储 - 所有这些都在运行时......但这样做是非常不寻常的。
您使用的接口位于运行时标头objc/runtime.h
中,您想要的呼叫是objc_allocateClassPair
,class_addMethod
,class_addIvar
等等。显然有很多要完成的工作是为了从XML描述中创建一个类及其布局,选择器等。因此,是的,这是可能的,但它不是免费的。