static VALUE rb_objc_alloc_class(const char *name, VALUE super, VALUE flags, VALUE klass) { char ocname[512] = { '\0' }; if (!rb_vm_generate_objc_class_name(name, ocname, sizeof ocname)) { goto no_more_classes; } Class ocklass = objc_allocateClassPair((Class)super, ocname, 0); if (ocklass == NULL) { goto no_more_classes; } long version_flag = RCLASS_IS_RUBY_CLASS; if (flags == T_MODULE) { version_flag |= RCLASS_IS_MODULE; } RCLASS_SET_VERSION(ocklass, version_flag); objc_registerClassPair(ocklass); if (klass != 0 && super != 0) { rb_objc_class_sync_version(ocklass, (Class)super); } return (VALUE)ocklass; no_more_classes: rb_raise(rb_eRuntimeError, "can't create new classes"); }
//Create an class named "AppDelegate", and return it's name as an instance of class NSString void *createAppDelegate() { Class mySubclass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "AppDelegate", 0); struct objc_selector *selName = sel_registerName("application:didFinishLaunchingWithOptions:"); class_addMethod(mySubclass, selName, (void(*))applicationdidFinishLaunching, nil); objc_registerClassPair(mySubclass); return objc_msgSend(objc_getClass("NSString"), sel_registerName("stringWithUTF8String:"), "AppDelegate"); }
void * createDelegate() { Class superclass = (Class) objc_getClass("NSObject"); Class DataSource = objc_allocateClassPair(superclass, "Delegate", 0); class_addMethod(DataSource, sel_registerName("tableView:didSelectRowAtIndexPath:"), (void(*))tableView_didSelectRowAtIndexPath, nil); objc_registerClassPair(DataSource); return class_createInstance(DataSource, 0); }
int main(int argc,const char* argv[]) { //新创建一个Class对象,继承于NSObject,名字叫NSPower(用于注册一个Class,Class的名字叫NSPower) Class powerCls = objc_allocateClassPair(objc_getClass("NSObject"), "NSPower", 0); //定义一个SEL,也就是OC里面的Selector,我理解为一个方法的Key,通过这个名字可以找到一个对应的方法实现函数 SEL selFun = sel_registerName("fun"); //为这个Class添加一个方法,名字叫fun,实现为power_fun(之前声明的一个C函数) //后面这个字符串是干嘛的呢?用来说明参数的,OC语言特别为每种参数类型指定了一个编码 //比如V@:的意思是,返回值是void,第一个参数是id,第二个参数是SEL class_addMethod(powerCls, selFun, (IMP)power_fun, "V@:"); //注册这个Class,从此以后,你就可以使用NSPower这个名字来创建一个类的实例了 objc_registerClassPair(powerCls); //以下代码就是创建一个NSPower的实例,并且调用fun方法 //得到一个class的实例 Class cls = objc_getClass("NSPower"); //对这个class发送alloc消息,创建一个class对象 id obj = objc_msgSend((id)cls,sel_registerName("alloc")); //对这个对象发送一个fun消息,这样会调用到之前的power_fun方法 objc_msgSend(obj,selFun); return 0; }
void *createDataSource() { Class superclass = (Class) objc_getClass("NSObject"); Class DataSource = objc_allocateClassPair(superclass, "DataSource", 0); class_addMethod(DataSource, sel_registerName("tableView:numberOfRowsInSection:"), (void(*))tableView_numberOfRowsInSection, nil); class_addMethod(DataSource, sel_registerName("tableView:cellForRowAtIndexPath:"), (void(*))tableView_cellForRowAtIndexPath, nil); objc_registerClassPair(DataSource); return class_createInstance(DataSource, 0); }
Class RegisterClass(old_class* cls, bool hasExt) { LOG << "Processing old ObjC class " << cls->name << std::endl; const old_class* meta = cls->isa.cls; Class conv, super; auto & g_classPointers = getClassPointers(); /* old_class* psuper = cls->super_class.cls; auto itSuper = g_classPointers.find(psuper); // TODO: may not be needed, should always be a string if (itSuper != g_classPointers.end()) super = itSuper->second; else super = reinterpret_cast<Class>(psuper); */ super = (Class) objc_getClass(cls->super_class.name); LOG << "...with superclass @" << super << std::endl; conv = objc_allocateClassPair(super, cls->name, 0); if (cls->methodList) ConvertMethodListGen(conv, cls->methodList); if (meta->methodList) ConvertMethodListGen(object_getClass(id(conv)), meta->methodList); if (cls->ivars) ConvertIvarList(conv, cls->ivars); if (cls->protocols) AddClassProtocols(conv, cls->protocols); if (hasExt && cls->ext && cls->ext->propertyLists) { LOG << "Class has EXT and a property list/lists\n"; //if (cls->info & CLS_NO_PROPERTY_ARRAY) if (true) { ConvertProperties(cls->ext->propertyList, [conv](const char* name, const objc_property_attribute_t* attr, unsigned int count) { class_addProperty(conv, name, attr, count); bug_gnustepFixPropertyCount(conv); }); } else { for (size_t i = 0; cls->ext->propertyLists[i] != nullptr; i++) { const old_property_list* l = cls->ext->propertyLists[i]; ConvertProperties(l, [conv](const char* name, const objc_property_attribute_t* attr, unsigned int count) { class_addProperty(conv, name, attr, count); bug_gnustepFixPropertyCount(conv); }); } } } objc_registerClassPair(conv); g_classPointers[cls] = conv; g_classPointers[cls->name] = conv; LOG << "ObjC class " << cls->name << " @" << conv << std::endl; return conv; }
Class RegisterClass(const class_t* cls, intptr_t slide) { LOG << "Processing ObjC class " << cls->data()->className << std::endl; const class_t* meta = cls->isa; Class conv, super; auto itSuper = g_classPointers.find(cls->superclass); if (itSuper != g_classPointers.end()) super = itSuper->second; else super = reinterpret_cast<Class>(cls->superclass); LOG << "...superclass is @" << super << std::endl; assert(objc_getClass(cls->data()->className) == nullptr); conv = objc_allocateClassPair(super, cls->data()->className, 0); const class_ro_t* ro = cls->data(); const class_ro_t* roMeta = meta->data(); if (ro->baseMethods) ConvertMethodListGen(conv, ro->baseMethods); if (roMeta->baseMethods) ConvertMethodListGen(object_getClass(id(conv)), roMeta->baseMethods); if (ro->ivars) ConvertIvarList(conv, ro->ivars); if (ro->baseProtocols) AddClassProtocols(conv, ro->baseProtocols, slide); if (ro->baseProperties) { ConvertProperties(ro->baseProperties, [conv](const char* name, const objc_property_attribute_t* attr, unsigned int count) { class_addProperty(conv, name, attr, count); bug_gnustepFixPropertyCount(conv); }); } // conv->instance_size = ro->instSize; // conv->isa->instance_size = roMeta->instSize; objc_registerClassPair(conv); LOG << "ObjC class " << cls->data()->className << " now @" << conv << std::endl; g_classPointers[cls] = conv; g_classPointers[cls->isa] = object_getClass(id(conv)); return conv; }
void* UndefMgr::generateNew(const char* name) { bool isClass = (strncmp(name, "OBJC_CLASS", 10) == 0); bool isMetaClass = (strncmp(name, "OBJC_METACLASS", 14) == 0); if (isClass || isMetaClass) { // Strip the OBJC_CLASS_$_ or OBJC_METACLASS_$_ name = &name[(isMetaClass) ? 17 : 13]; // Objective-C class or metaclass info static std::map<std::string, Class> undefClasses; Class classStub = nullptr; auto classIter = undefClasses.find(name); if (classIter != undefClasses.end()) { classStub = classIter->second; } else if (NULL == (classStub = (Class)objc_getClass(name))) { classStub = objc_allocateClassPair(nullptr, name, 0); if (isMetaClass) { // Put in a dummy initialize method that lets us know the class got used IMP imp = reinterpret_cast<IMP>(&UndefinedClassInitialize); SEL sel = sel_registerTypedName_np("initialize", NULL); class_addMethod(object_getClass(reinterpret_cast<id>(classStub)), sel, imp, NULL); } objc_registerClassPair(classStub); Darling::MachOMgr::instance()->registerNativeClass(object_getClass(reinterpret_cast<id>(classStub))); Darling::MachOMgr::instance()->registerNativeClass(classStub); fprintf(stderr, "Undef class for class %s at %p\n", class_getName(classStub), classStub); undefClasses[name] = classStub; } return (isClass) ? classStub : object_getClass(reinterpret_cast<id>(classStub)); } else if (strncmp(name, "OBJC_IVAR", 9) == 0) { // Objective-C ivar typedef struct { const char *name; const char *type; int offset; } objc_ivar; objc_ivar *ivarStub = new objc_ivar; ivarStub->name = &name[12]; ivarStub->type = ""; ivarStub->offset = 0; return ivarStub; } else { // Generate a function stub UndefinedFunction * uf = new UndefinedFunction(); uf->init(name); return uf->getPointer(); } }
Class RegisterClass(const class_t* cls, intptr_t slide, uint32_t image_index) { if (nullptr == cls) { return nullptr; } auto & g_classPointers = getClassPointers(); auto itClass = g_classPointers.find(cls); if (itClass != g_classPointers.end()) { LOG << "Found existing class @" << itClass->second << std::endl; return itClass->second; } Class super = RegisterClass(cls->superclass, slide, image_index); LOG << "...superclass is @" << super << std::endl; if (nullptr != super) { LOG << "...superclass name " << (((uintptr_t)super != (uintptr_t)cls->superclass) ? cls->superclass->data()->className : class_getName(super)) << std::endl; LOG << "...super name " << class_getName(super) << std::endl; } if (nullptr == cls->data()) { // TODO: Is this a bad pointer filled in, or are we supposed to do something different with this? // This is from when we call RegisterClass recursively sometimes... std::cerr << "Error - Null class data at class @" << cls << std::endl; return nullptr; } if (nullptr == cls->data()->className) { // TODO: Is this a bad pointer filled in, or are we supposed to do something different with this? // This is from when we call RegisterClass recursively sometimes... std::cerr << "Error - Null class name at class @" << cls << std::endl; return nullptr; } LOG << "Processing ObjC class " << cls->data()->className << std::endl; Class sameClass = (Class)objc_getClass(cls->data()->className); if (nullptr != sameClass) { LOG << "Found a class with the same name @" << sameClass << std::endl; return sameClass; } LOG << "obj_allocateClassPair(" << super << ", " << cls->data()->className << ")" << std::endl; Class conv = objc_allocateClassPair(super, cls->data()->className, 0); if (nullptr == conv) { std::cerr << "Failed to allocate class " << cls->data()->className << std::endl; return nullptr; } Class meta = object_getClass(id(conv)); const class_ro_t* ro = cls->data(); if (ro->baseMethods) ConvertMethodListGen(conv, ro->baseMethods, image_index); if (g_classPointers.find(cls->isa) == g_classPointers.end()) { const class_ro_t* roMeta = cls->isa->data(); if (roMeta->baseMethods) ConvertMethodListGen(meta, roMeta->baseMethods, image_index); } if (ro->ivars) ConvertIvarList(conv, ro->ivars); if (ro->baseProtocols) AddClassProtocols(conv, ro->baseProtocols, slide); if (ro->baseProperties) { ConvertProperties(ro->baseProperties, [conv](const char* name, const objc_property_attribute_t* attr, unsigned int count) { class_addProperty(conv, name, attr, count); bug_gnustepFixPropertyCount(conv); }); } // conv->instance_size = ro->instSize; objc_registerClassPair(conv); LOG << "ObjC class " << cls->data()->className << " now @" << conv << std::endl; g_classPointers[cls] = conv; g_classPointers[conv] = conv; g_classPointers[meta] = meta; return conv; }
bool NSGLWindow::initialize() { // Strong reference to the class of the AppDelegate (same as [AppDelegate class]) static Class appDelClass = nullptr; if (not appDelClass) { appDelClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "AppDelegate", 0); class_addMethod(appDelClass, sel_getUid("applicationDidFinishLaunching:"), (IMP)OnAppDidFinishLaunching, "i@:@"); objc_registerClassPair(appDelClass); } // Tell the runtime to create a new class, a subclass of 'NSOpenGLView' named 'YView'. static Class viewClass = nullptr; if (not viewClass) { viewClass = objc_allocateClassPair((Class)objc_getClass("NSOpenGLView"), "YView", 0); // Tell the runtime to add functions for various events to our custom view. class_addMethod(viewClass, sel_getUid("drawRect:"), (IMP)NSGLWindow::OnDrawRect, "v@:"); class_addMethod(viewClass, sel_getUid("mouseDown:"), (IMP)NSGLWindow::OnMouseDown, "v@:"); //class_addMethod(viewClass, sel_getUid("close:"), (IMP)NSGLWindow::OnWindowClose, "v@:"); // And again, we tell the runtime that this class is now valid to be used. // At this point, the application should run and display the screenshot shown below. objc_registerClassPair(viewClass); } cmacs_simple_msgSend((id)objc_getClass("NSApplication"), sel_getUid("sharedApplication")); if (not NSApp) { std::cerr << "Failed to initialized NSApplication... terminating..." << std::endl; return false; } // Create the app delegate static AppDelegate* appDelObj = nullptr; if (not appDelObj) { appDelObj = (AppDelegate*)cmacs_simple_msgSend((id)objc_getClass("AppDelegate"), sel_getUid("alloc")); appDelObj = (AppDelegate*)cmacs_simple_msgSend((id)appDelObj, sel_getUid("init")); cmacs_void_msgSend1(NSApp, sel_getUid("setDelegate:"), appDelObj); // Launch main loop //cmacs_void_msgSend(NSApp, sel_getUid("run")); } appDelObj->window = cmacs_simple_msgSend((id)objc_getClass("NSOpenGLWindow"), sel_getUid("alloc")); /// Create an instance of the window. appDelObj->window = cmacs_window_init_msgSend(appDelObj->window, sel_getUid("initWithContentRect:styleMask:backing:defer:"), (CMRect){ {0,0},{1024,460}}, (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask), 0, false); /// Create an instance of our view class. /// /// Relies on the view having declared a constructor that allocates a class pair for it. id view = cmacs_rect_msgSend1(cmacs_simple_msgSend((id)objc_getClass("YView"), sel_getUid("alloc")), sel_getUid("initWithFrame:"), (CMRect){ {0, 0}, {640, 480} }); // here we simply add the view to the window. cmacs_void_msgSend1(appDelObj->window, sel_getUid("setContentView:"), view); cmacs_simple_msgSend(appDelObj->window, sel_getUid("becomeFirstResponder")); // Shows our window in the bottom-left hand corner of the screen. //cmacs_void_msgSend1(appDelObj->window, sel_getUid("makeKeyAndOrderFront:"), appDelObj); return true; }