Reputation: 7476
Is it possible to define classes at run time in objective-c?
E.g. I receive an XML file, that defines an object and create it and use it in run-time?
Upvotes: 4
Views: 1351
Reputation: 55583
Yes, check this code snippet out, I created a class here, using only C methods, and one protocol definition (for simplicity when making message calls)...
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;
}
Usage:
MyCObj obj = [MyCObj_class new];
NSLog(@"%@ %i %@", [obj getString], [obj getInt], [MyCObj_class someStaticMethod]);
Upvotes: 6
Reputation: 104698
yes, you can use the objc runtime to create a type, define methods and its storage-- all at runtime... it's very unusual to do this, however.
the interfaces you use are in the runtime headers objc/runtime.h
, and the calls you want are objc_allocateClassPair
, class_addMethod
, class_addIvar
, etc. there's obviously quite a bit of work to be done in order create a class and its layout, selectors, and such from an XML description. Therefore, yes it is possible, but it's not free.
Upvotes: 2
Reputation: 162722
Yes; completely possible. See the Objective-C Runtime Programming Guide for details (including the related guides & docs).
As Justin said, it is extremely atypical to go this route. If you are loading XML data, it is almost always the cast that said XML must have a well defined structure -- a strict DTD or schema -- and, thus, you would be much better off with a disciplined, well defined, data model compiled into your app (via Core Data or direct implementation) that you load the XML against. This allows for tighter validation and will be significantly easier.
The holy grail of "free form data consumption" is oft tempting, but down that path lies madness and many tales of woe.
Upvotes: 5