Created
May 5, 2012 04:02
-
-
Save andreyvit/2599564 to your computer and use it in GitHub Desktop.
Fake an Objective-C class out of a C++ class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Fakes an Objective-C class out of a C++ class. | |
// | |
// Note that this is a very bad and completely superfluous idea, but after looking up a way | |
// to build Objective-C classes at run time, I just had to do this no matter what. (Besides, | |
// I really hated maintaining mutual pointers in UIElement/UIElementDelegate class pairs.) | |
// | |
// Building up a whole class from scratch (objc_allocateClassPair) looked like a lot of trouble, | |
// so I compile a real Objective-C class instead, but instead of instantiating it by regular means | |
// (alloc/init or class_createInstance), I simply cast a part of a C++ object to (id). | |
// I've looked at the source code for class_createInstance and this hack should work perfectly, | |
// but of course we're relying on a private implementation detail of Objective-C runtime here. | |
// | |
// The beauty is that if I inherit from ObjCObject, I can let C++ figure out the pointer arithmetic | |
// necessary to convert between (SomeUIElement *) and (ObjCObject *, aka id). | |
// | |
// Our use case is so trivial that it makes no sense to apply any kind of tricks here. However, | |
// again, I couldn't help myself, and hey, it's my product, I want to have fun writing it. | |
class ObjCObject { | |
public: | |
Class isa; | |
// NSObject holds reference counts in a separate hashtable, so we don't need to allocate space for that | |
ObjCObject(Class isa) { | |
this->isa = isa; | |
} | |
id self() { | |
return (id)this; | |
} | |
template <typename T> | |
static T *from_id(id obj) { | |
return static_cast<T *>(reinterpret_cast<ObjCObject *>(obj)); | |
} | |
private: | |
// CoreFoundation wants ObjC classes to be at least 16 bytes in length, | |
void *_cf_filler[3]; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// usage example: | |
class WindowUIElement : public UIElement, public ObjCObject { ... }; | |
@interface WindowUIElementDelegate : NSObject <NSWindowDelegate> | |
@end | |
WindowUIElement::WindowUIElement(...) : UIElement(...), ObjCObject([WindowUIElementDelegate class]) { | |
} | |
void WindowUIElement::some_method() { | |
[my_window_ setDelegate:self()]; | |
} | |
@implementation WindowUIElementDelegate | |
- (void)windowDidBecomeKey:(NSNotification *)notification { | |
WindowUIElement *that = ObjCObject::from_id<WindowUIElement>(self); | |
... | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment