Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Objective-C is a superset of the C-language, so it is theoretically possible to write a program entirely in C, however, unless you are thoroughly versed in <code>OpenGL ES</code>, You'll need to do at least <strong><em>some</em></strong> objC (<strike>Even Rich's sample has a const NSString* in it</strike>), else you'll have to write the views yourself.</p> <p>OK, the above is completely wrong. Let me say, I'm astounded Rich achieved this lofty goal, so I ported it over to the mac (source <a href="https://github.com/CodaFi/C-Macs" rel="noreferrer">here</a>). The files below have no headers, do not link to Cocoa, nor does the project have a nib:</p> <p><strong>AppDelegate.m</strong></p> <pre><code>#include &lt;objc/runtime.h&gt; #include &lt;objc/message.h&gt; extern id NSApp; struct AppDel { Class isa; //Will be an NSWindow later, for now, it's id, because we cannot use pointers to ObjC classes id window; }; // This is a strong reference to the class of the AppDelegate // (same as [AppDelegate class]) Class AppDelClass; BOOL AppDel_didFinishLaunching(struct AppDel *self, SEL _cmd, id notification) { //alloc NSWindow self-&gt;window = objc_msgSend(objc_getClass("NSWindow"), sel_getUid("alloc")); //init NSWindow //Adjust frame. Window would be about 50*50 px without this //specify window type. We want a resizeable window that we can close. //use retained backing because this thing is small anyhow //return no because this is the main window, and should be shown immediately self-&gt;window = objc_msgSend(self-&gt;window, sel_getUid("initWithContentRect:styleMask:backing:defer:"),(NSRect){0,0,1024,460}, (NSTitledWindowMask|NSClosableWindowMask|NSResizableWindowMask|NSMiniaturizableWindowMask),NSBackingStoreRetained,NO); //send alloc and init to our view class. Love the nested objc_msgSends! id view = objc_msgSend(objc_msgSend(objc_getClass("View"), sel_getUid("alloc")), sel_getUid("initWithFrame:"), (struct CGRect) { 0, 0, 320, 480 }); // here we simply add the view to the window. objc_msgSend(self-&gt;window, sel_getUid("setContentView:"), view); objc_msgSend(self-&gt;window, sel_getUid("becomeFirstResponder")); //makeKeyOrderFront: NSWindow to show in bottom left corner of the screen objc_msgSend(self-&gt;window, sel_getUid("makeKeyAndOrderFront:"), self); return YES; } static void initAppDel() { //Our appDelegate should be NSObject, but if you want to go the hard route, make this a class pair of NSApplication and try initing those awful delegate methods! AppDelClass = objc_allocateClassPair((Class) objc_getClass("NSObject"), "AppDelegate", 0); //Change the implementation of applicationDidFinishLaunching: so we don't have to use ObjC when this is called by the system. class_addMethod(AppDelClass, sel_getUid("applicationDidFinishLaunching:"), (IMP) AppDel_didFinishLaunching, "i@:@"); objc_registerClassPair(AppDelClass); } void init_app(void) { objc_msgSend( objc_getClass("NSApplication"), sel_getUid("sharedApplication")); if (NSApp == NULL) { fprintf(stderr,"Failed to initialized NSApplication... terminating...\n"); return; } id appDelObj = objc_msgSend( objc_getClass("AppDelegate"), sel_getUid("alloc")); appDelObj = objc_msgSend(appDelObj, sel_getUid("init")); objc_msgSend(NSApp, sel_getUid("setDelegate:"), appDelObj); objc_msgSend(NSApp, sel_getUid("run")); } //there doesn't need to be a main.m because of this little beauty here. int main(int argc, char** argv) { //Initialize a valid app delegate object just like [NSApplication sharedApplication]; initAppDel(); //Initialize the run loop, just like [NSApp run]; this function NEVER returns until the app closes successfully. init_app(); //We should close acceptably. return EXIT_SUCCESS; } </code></pre> <p><strong>View.m</strong></p> <pre><code>#include &lt;objc/runtime.h&gt; #include &lt;objc/message.h&gt; #include &lt;ApplicationServices/ApplicationServices.h&gt; // This is a strong reference to the class of our custom view, // In case we need it in the future. Class ViewClass; // This is a simple -drawRect implementation for our class. We could have // used a UILabel or something of that sort instead, but I felt that this // stuck with the C-based mentality of the application. void View_drawRect(id self, SEL _cmd, CGRect rect) { //make a red NSColor object with its convenience method id red = objc_msgSend(objc_getClass("NSColor"), sel_getUid("redColor")); // fill target rect with red, because this is it! NSRect rect1 = NSMakeRect ( 21,21,210,210 ); objc_msgSend(red, sel_getUid("set")); NSRectFill ( rect1 ); } // Once again we use the (constructor) attribute. generally speaking, // having many of these is a very bad idea, but in a small application // like this, it really shouldn't be that big of an issue. __attribute__((constructor)) static void initView() { // Once again, just like the app delegate, we tell the runtime to // create a new class, this time a subclass of 'UIView' and named 'View'. ViewClass = objc_allocateClassPair((Class) objc_getClass("NSView"), "View", 0); // and again, we tell the runtime to add a function called -drawRect: // to our custom view. Note that there is an error in the type-specification // of this method, as I do not know the @encode sequence of 'CGRect' off // of the top of my head. As a result, there is a chance that the rect // parameter of the method may not get passed properly. class_addMethod(ViewClass, sel_getUid("drawRect:"), (IMP) View_drawRect, "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); } </code></pre> <p><strong>prefix.pch</strong></p> <pre><code>// // Prefix header for all source files of the 'CBasedMacApp' target in the 'CBasedMacApp' project // #ifdef __OBJC__ #import &lt;Foundation/Foundation.h&gt; #import &lt;AppKit/AppKit.h&gt; #endif </code></pre> <p><img src="https://i.stack.imgur.com/umwxu.png" alt="enter image description here"></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload