4

I know it is possible to use Objective C code using objc_msgSend to, I believe, manually run the Objective C runtime however when I run this code I get errors referencing NSString (even though I never use it) as well as other un-used classes.

Errors from xcode

enter image description here

I have the Objective C Code above it (commented out) that I am trying to 'mimic'.

#include <Foundation/Foundation.h> /*Added suggestion by answer, same errors*/
#include <AppKit/AppKit.h>

int main()
{
// convert objective c into c code
/*
    NSAlert *alert = [[NSAlert alloc] init];
    [alert setAlertStyle:NSInformationalAlertStyle];
    [alert setMessageText:@"Hello World"];
    [alert setInformativeText:@"Hello World"];
    [alert runModal];
*/
    id alert = objc_msgSend(objc_msgSend(objc_getClass("NSAlert"), sel_registerName("alloc")), sel_registerName("init"));
    objc_msgSend(alert, sel_getUid("setAlertStyle:"), NSInformationalAlertStyle);
    objc_msgSend(alert, sel_getUid("setMessageText:"), CFSTR("Hello World!"));
    objc_msgSend(alert, sel_getUid("setInformativeText:"), CFSTR("Hello World!"));
    objc_msgSend(alert, sel_getUid("runModal"));
}
Zimm3r
  • 3,263
  • 4
  • 31
  • 50
  • 3
    While a useful learning exercise, this is otherwise pretty pointless. The equivalent code still depends on the ObjC runtime and, thus, the app will still be an ObjC based application. Just change the extension from `.c` to `.m` and be done with it. – bbum Sep 09 '13 at 00:18
  • @bbum How do you mean? The whole goal of this is so I can write in NASM and not use the god awful language that only apple could make that is objective c. – Zimm3r Sep 09 '13 at 02:41
  • 1
    Do not call objc_msgSend() without a cast to a function pointer type that matches the method's signature. – Greg Parker Sep 09 '13 at 03:05
  • @Zimm3r The entire UI of both OS X and iOS are built around object oriented principals that happen to be realized in Objective-C. Subclassing, delegation, observation, introspection, etc.etc.etc.. will be unavoidable in any large scale app. While all can be done without writing a single line of ObjC, you'll be re-inventing the wheel at every step and likely doing so with more code that is less maintainable & completely alien to the myriad of developers familiar with the platform. Even with this dead simple example (which doesn't work correctly, btw), you're already using ObjC heavily. – bbum Sep 09 '13 at 05:17

1 Answers1

5

You are missing some imports.

objc_msgSend is declared in <objc/message.h>.

objc_getClass is declared in <objc/runtime.h>.

sel_getUid and sel_registerName are declared in <objc/objc.h>.

Now, given that <objc/objc.h> is already imported by <objc/runtime.h>, importing the latter along with <objc/message.h> should suffice.

I tested it with the following example and it works as expected

#include <CoreFoundation/CoreFoundation.h> // Needed for CFSTR
#include <objc/runtime.h>
#include <objc/message.h>

int main(int argc, char *argv[]) {
    id alert = (id (*)(id, SEL))objc_msgSend((id (*)(id, SEL))objc_msgSend(objc_getClass("NSAlert"), sel_registerName("alloc")), sel_registerName("init"));
    (void (*)(id, SEL, int))objc_msgSend(alert, sel_getUid("setAlertStyle:"), 1); // NSInformationalAlertStyle is defined in AppKit, so let's just use 1
    (void (*)(id, SEL, id))objc_msgSend(alert, sel_getUid("setMessageText:"), CFSTR("Hello World!"));
    (void (*)(id, SEL, id))objc_msgSend(alert, sel_getUid("setInformativeText:"), CFSTR("Hello World!"));
    (int (*)(id, SEL))objc_msgSend(alert, sel_getUid("runModal"));
}

Note

I added the explicit cast to objc_msgSend as suggested by Greg Parker in the comments.

Gabriele Petronella
  • 104,800
  • 21
  • 210
  • 229