如何在C中纯粹编写iOS应用程序
本文翻译自:How to write iOS app purely in C
I read here Learn C Before Objective-C? 我在这里读到在Objective-C之前学习C?
Usually I then replace some Obj-C code with pure C code (after all you can mix them as much as you like, the content of an Obj-C method can be entirely, pure C code) 通常我会用纯C代码替换一些Obj-C代码(毕竟你可以根据需要混合它们,Obj-C方法的内容可以完全是纯C代码)
Is this true? 这是真的?
Is it possible to build an iPhone app purely in the C programming language? 是否有可能纯粹使用C编程语言构建iPhone应用程序?
#1楼
参考:https://stackoom.com/question/hAry/如何在C中纯粹编写iOS应用程序
#2楼
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 OpenGL ES
, You'll need to do at least some objC ( Even Rich's sample has a const NSString* in it ), else you'll have to write the views yourself. Objective-C是C语言的超集,因此理论上可以用C语言编写程序,但是,除非你精通OpenGL ES
,否则你至少需要做一些 objC( Even Rich的样本)其中有一个const NSString * ,否则你必须自己编写视图。
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 here ). 让我说,我很震惊Rich实现了这个崇高的目标,所以我把它移植到了mac(来源这里 )。 The files below have no headers, do not link to Cocoa, nor does the project have a nib: 下面的文件没有标题,不链接到Cocoa,项目也没有nib:
AppDelegate.m AppDelegate.m
#include <objc/runtime.h>
#include <objc/message.h>extern id NSApp;struct AppDel
{Class isa;//Will be an NSWindow later, for now, it's id, because we cannot use pointers to ObjC classesid 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 NSWindowself->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 immediatelyself->window = objc_msgSend(self->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->window, sel_getUid("setContentView:"), view);objc_msgSend(self->window, sel_getUid("becomeFirstResponder"));//makeKeyOrderFront: NSWindow to show in bottom left corner of the screenobjc_msgSend(self->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;
}
View.m View.m
#include <objc/runtime.h>
#include <objc/message.h>
#include <ApplicationServices/ApplicationServices.h>// 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 methodid 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);
}
prefix.pch prefix.pch
//
// Prefix header for all source files of the 'CBasedMacApp' target in the 'CBasedMacApp' project
//#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#endif
#3楼
Damn, it took me a while but I got it: 该死的,我花了一段时间,但我得到了它:
main.c: main.c中:
#include <CoreFoundation/CoreFoundation.h>#include <objc/runtime.h>
#include <objc/message.h>// This is a hack. Because we are writing in C, we cannot out and include
// <UIKit/UIKit.h>, as that uses Objective-C constructs.
// however, neither can we give the full function declaration, like this:
// int UIApplicationMain (int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
// So, we rely on the fact that for both the i386 & ARM architectures,
// the registers for parameters passed in remain the same whether or not
// you are using VA_ARGS. This is actually the basis of the objective-c
// runtime (objc_msgSend), so we are probably fine here, this would be
// the last thing I would expect to break.
extern int UIApplicationMain(int, ...);// Entry point of the application. If you don't know what this is by now,
// then you probably shouldn't be reading the rest of this post.
int main(int argc, char *argv[])
{// Create an @autoreleasepool, using the old-stye API. // Note that while NSAutoreleasePool IS deprecated, it still exists // in the APIs for a reason, and we leverage that here. In a perfect // world we wouldn't have to worry about this, but, remember, this is C.id autoreleasePool = objc_msgSend(objc_msgSend(objc_getClass("NSAutoreleasePool"), sel_registerName("alloc")), sel_registerName("init"));// Notice the use of CFSTR here. We cannot use an objective-c string // literal @"someStr", as that would be using objective-c, obviously.UIApplicationMain(argc, argv, nil, CFSTR("AppDelegate"));objc_msgSend(autoreleasePool, sel_registerName("drain"));
}
AppDelegate.c: AppDelegate.c:
#import <objc/runtime.h>
#import <objc/message.h>// This is equivalent to creating a @class with one public variable named 'window'.
struct AppDel
{Class isa;id window;
};// This is a strong reference to the class of the AppDelegate
// (same as [AppDelegate class])
Class AppDelClass;// this is the entry point of the application, same as -application:didFinishLaunchingWithOptions:
// note the fact that we use `void *` for the 'application' and 'options' fields, as we need no reference to them for this to work. A generic id would suffice here as well.
BOOL AppDel_didFinishLaunching(struct AppDel *self, SEL _cmd, void *application, void *options)
{// we +alloc and -initWithFrame: our window here, so that we can have it show on screen (eventually).// this entire method is the objc-runtime based version of the standard View-Based application's launch code, so nothing here really should surprise you.// one thing important to note, though is that we use `sel_getUid()` instead of @selector().// this is because @selector is an objc language construct, and the application would not have been created in C if I used @selector.self->window = objc_msgSend(objc_getClass("UIWindow"), sel_getUid("alloc"));self->window = objc_msgSend(self->window, sel_getUid("initWithFrame:"), (struct CGRect) { 0, 0, 320, 480 });// here, we are creating our view controller, and our view. note the use of objc_getClass, because we cannot reference UIViewController directly in C.id viewController = objc_msgSend(objc_msgSend(objc_getClass("UIViewController"), sel_getUid("alloc")), sel_getUid("init"));// creating our custom view class, there really isn't too much // to say here other than we are hard-coding the screen's bounds, // because returning a struct from a `objc_msgSend()` (via // [[UIScreen mainScreen] bounds]) requires a different function call// and is finicky at best.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 view controller, and add the viewController to the window.objc_msgSend(objc_msgSend(viewController, sel_getUid("view")), sel_getUid("addSubview:"), view);objc_msgSend(self->window, sel_getUid("setRootViewController:"), viewController);// finally, we display the window on-screen.objc_msgSend(self->window, sel_getUid("makeKeyAndVisible"));return YES;
}// note the use of the gcc attribute extension (constructor).
// Basically, this lets us run arbitrary code before program startup,
// for more information read here: http://stackoverflow.com/questions/2053029
__attribute__((constructor))
static void initAppDel()
{// This is objc-runtime gibberish at best. We are creating a class with the // name "AppDelegate" that is a subclass of "UIResponder". Note we do not need// to register for the UIApplicationDelegate protocol, that really is simply for // Xcode's autocomplete, we just need to implement the method and we are golden.AppDelClass = objc_allocateClassPair(objc_getClass("UIResponder"), "AppDelegate", 0);// Here, we tell the objc runtime that we have a variable named "window" of type 'id'class_addIvar(AppDelClass, "window", sizeof(id), 0, "@");// We tell the objc-runtime that we have an implementation for the method// -application:didFinishLaunchingWithOptions:, and link that to our custom // function defined above. Notice the final parameter. This tells the runtime// the types of arguments received by the function.class_addMethod(AppDelClass, sel_getUid("application:didFinishLaunchingWithOptions:"), (IMP) AppDel_didFinishLaunching, "i@:@@");// Finally we tell the runtime that we have finished describing the class and // we can let the rest of the application use it.objc_registerClassPair(AppDelClass);
}
View.c View.c
#include <objc/runtime.h>// 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, struct CGRect rect)
{// We are simply getting the graphics context of the current view, // so we can draw to itCGContextRef context = UIGraphicsGetCurrentContext();// Then we set it's fill color to white so that we clear the background.// Note the cast to (CGFloat []). Otherwise, this would give a warning// saying "invalid cast from type 'int' to 'CGFloat *', or // 'extra elements in initializer'. Also note the assumption of RGBA.// If this wasn't a demo application, I would strongly recommend against this,// but for the most part you can be pretty sure that this is a safe move // in an iOS application.CGContextSetFillColor(context, (CGFloat []){ 1, 1, 1, 1 });// here, we simply add and draw the rect to the screenCGContextAddRect(context, (struct CGRect) { 0, 0, 320, 480 });CGContextFillPath(context);// and we now set the drawing color to red, then add another rectangle// and draw to the screenCGContextSetFillColor(context, (CGFloat []) { 1, 0, 0, 1 });CGContextAddRect(context, (struct CGRect) { 10, 10, 20, 20 });CGContextFillPath(context);
}// 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(objc_getClass("UIView"), "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);
}
It's ugly, but it works. 这很难看,但它确实有效。
If you would like to download this, you can get it from my dropbox here 如果您想下载此内容, 可以在此处从我的保管箱中获取
You can get it from my GitHub repository here : 你可以从我的GitHub库得到它在这里 :
#4楼
I read here Learn C Before Objective-C? 我在这里读到在Objective-C之前学习C?
Usually I then replace some Obj-C code with pure C code (after all you can mix them as much as you like, the content of an Obj-C method can be entirely, pure C code) 通常我会用纯C代码替换一些Obj-C代码(毕竟你可以根据需要混合它们,Obj-C方法的内容可以完全是纯C代码)
Is this true? 这是真的?
Could I build an iPhone app purely in the C programming language? 我可以纯粹用C编程语言构建一个iPhone应用程序吗?
The quoted passage is true, but the answer to your question is no. 引用的段落是正确的,但你的问题的答案是否定的。
To illustrate what answerer Mecki on that other question was talking about: 为了说明Mecki对另一个问题的回答:
- (void) drawRect:(CGRect)dirtyRect { //Objective-CCGContextRef context = UIGraphicsGetCurrentContext(); //CCGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0); //CCGContextFillRect(context, dirtyRect); //C} //Objective-C (balances above “- (void) drawRect:…” line)
There is nothing but pure C code within this method, but the method itself is Objective-C code, as is the class that contains this method. 没有什么,但纯C代码, 在此方法中 ,但该方法本身是Objective-C代码,如包含此方法的类。
So it is possible to do what Mecki said, but you can't (practically—as Richard J. Ross III showed, it's technically possible but quite a lot of typing) write a whole Cocoa Touch program in pure C. 所以有可能做到Mecki所说的,但你不能(实际上 - 正如理查德J.罗斯三世所展示的那样,技术上可行,但很多打字)在纯C中编写了一个完整的Cocoa Touch程序。
#5楼
Actually, some of the code posted here, while written in C, is still calling objective-C code :). 实际上,这里发布的一些代码,用C语言编写,仍然是调用Objective-C代码:)。 I don't know if that actually fits the scenario from the original poster when he asked 当他问道时,我不知道这是否真的符合原始海报的情景
Is it possible to build an iPhone app purely in the C programming language? 是否有可能纯粹使用C编程语言构建iPhone应用程序?
but I would agree with the people saying that, generally speaking and for an app with a GUI, you would need to write your GUI in OpenGL (which is C). 但我同意人们的说法,一般而言,对于带有GUI的应用程序,您需要在OpenGL中编写GUI(即C)。
I think that is what most games do, right? 我认为大多数游戏都是这样,对吧? Although I'm not sure if there's access to the iPhone's I/O (the touchscreen for example) in C. 虽然我不确定是否可以在C中访问iPhone的I / O(例如触摸屏)。
Last but not least, the guys that wrote the code above rock! 最后但并非最不重要的是,编写上面代码的人摇滚! :) :)
如何在C中纯粹编写iOS应用程序相关推荐
- 如何在 Python 中构建跨平台桌面应用程序
如何在 Python 中构建跨平台桌面应用程序 开发桌面 GUI 应用程序曾经是一个乏味.容易出错且缓慢的过程. 当然,Python 在整体上极大地简化了应用程序开发,但在 GUI 领域,仍然没有真正 ...
- ultraedit运行java_如何在UltraEdit中编译和运行Java程序
如何在UltraEdit中编译和运行Java程序 (2011-07-28 12:33:52) 标签: it 问题提出: 可以毫不夸张地说,JDK+UltraEdit是面向Java初学者的开发工具的绝配 ...
- 如何在IDEA中创建并部署JavaWeb程序
本文来说下如何在 IDEA 中创建并部署 JavaWeb 程序 文章目录 概述 概述
- 如何在 IDEA 中创建并部署 JavaWeb 程序
前言 在之前 Java 的学习中,我们可能更多地是和控制台程序打交道,也就是我们日常说的黑框框程序. 现在既然完成了 Java SE 部分的基础知识,是时候来学习 JavaWeb 部分.而随着 IDE ...
- chrome 插件火狐安装_如何在Firefox中安装任何Chrome扩展程序
chrome 插件火狐安装 Firefox is a great browser, but if you've ever eyed all those great Chrome extensions, ...
- 【Elasticsearch】如何在 Elasticsearch 中轻松编写脚本
随着 Elasticsearch 5.x 的发布,Painless 出现了,这是 Elasticsearch 对安全.可靠和高性能脚本编写的回答.我们将向您介绍 Painless 并向您展示它的功能. ...
- linux中终止停止进程_如何在Linux中终止进程或停止程序
linux中终止停止进程 当一个进程行为异常时,您有时可能想要终止或终止它. 在本文中,我们将探讨几种使用gedit作为示例应用程序从命令行以及图形界面终止进程或应用程序的方法. 使用命令行/终止符 ...
- r java_如何在R中使用JAVA写的程序包?
不过我对 Java 真的不太熟悉,按照教程调用这个 LLDA 包之后只会使用 inferencer. 如果你不嫌麻烦可以考虑先用 Java 计算出结果,然后在 R 中载入这些结果. 具体步骤如下: 0 ...
- 如何在matlab中表达点集,matlab练习程序(点集配准的SVD法)
上一篇博客中我们使用了四元数法计算ICP. 本篇我们使用SVD计算ICP. 下面是<视觉slam十四讲>中的计算方法: 计算步骤如下: 我们看到,只要求出了两组点之间的旋转,平移是非常容易 ...
最新文章
- 转载:DIV+CSS有可能遇到的问题
- 敏捷有效执行的关键软技能
- Swagger3.0
- 编写properties文件的Eclipse插件
- pytorch损失函数(正在更新中,勿点进来看)
- Emacs学习笔记(6):常用命令备忘(打印版)
- 使用Visual Studio Code + Node.js搭建TypeScript开发环境
- 防碰撞算法c语言,RFID防碰撞 二进制树形搜索算法 C语言实现
- tomcat遇到jre\lib\ext\localedata.pack 时出错
- python socket模块 和pyqt5_PyQt5+Socket实现CS架构的建议聊天室
- 公务员工资分配的一种方法
- Java中遍历Map集合的五种方式
- 勒索病毒解密工具的汇总
- c语言ad转换实验报告,苏州大学实验报告-实验四ad转换模块实验报告
- 机载激光雷达原理与应用科普(六)
- TRAS为springcloud提供高性能的RPC能力
- react app 拉起微信、支付宝支付
- 如何下载没有水印的小咖秀和晃咖视频?教你个超级简单的方法
- 【专升本计算机】甘肃省专升本考试公共课计算机填空题考点汇总
- 老司机 iOS 周报 #62 | 2019-04-08