可可中的自定义主应用程序循环

2024-03-10

我一直在关注 Handmade Hero 项目,其中 Casey Muratori 从头开始​​创建了一个完整的游戏引擎,而不使用库。 该引擎具有高度可移植性,因为它呈现自己的位图,然后平台特定的代码将其绘制到屏幕上。

在 Windows 下,通常有一个主应用程序循环,您可以在其中放置应重复执行的代码,直到应用程序终止。然而Cocoa中没有这样的东西。立刻[NSApp run];叫做int main()变得几乎没有用,你必须将代码放入委托方法中才能执行。 但这不是我想要的方式。我在网上找到了一些代码,其中有人已经完全按照我的要求做了,但代码有一些缺陷,或者可以说我只是不知道如何处理它。

#import <Cocoa/Cocoa.h>
#import <CoreGraphics/CoreGraphics.h>
#include <stdint.h>


#define internal static
#define local_persist static
#define global_variable static

typedef uint8_t uint8;

global_variable bool running = false;

global_variable void *BitmapMemory;
global_variable int BitmapWidth = 1024;
global_variable int BitmapHeight = 768;
global_variable int BytesPerPixel = 4;

global_variable int XOffset = 0;
global_variable int YOffset = 0;


@class View;
@class AppDelegate;
@class WindowDelegate;


global_variable AppDelegate *appDelegate;
global_variable NSWindow *window;
global_variable View *view;
global_variable WindowDelegate *windowDelegate;


@interface AppDelegate: NSObject <NSApplicationDelegate> {
}
@end

@implementation AppDelegate

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
    // Cocoa will kill your app on the spot if you don't stop it
    // So if you want to do anything beyond your main loop then include this method.
    running = false;
    return NSTerminateCancel;
}

@end


@interface WindowDelegate : NSObject <NSWindowDelegate> {
}
@end
@implementation WindowDelegate

- (BOOL)windowShouldClose:(id)sender {
    running = false;
    return YES;
}

-(void)windowWillClose:(NSNotification *)notification {
    if (running) {
        running = false;
        [NSApp terminate:self];
    }
}

@end




@interface View : NSView <NSWindowDelegate> {
@public
    CGContextRef backBuffer_;
}
- (instancetype)initWithFrame:(NSRect)frameRect;
- (void)drawRect:(NSRect)dirtyRect;
@end

@implementation View
// Initialize
- (id)initWithFrame:(NSRect)frameRect {
    self = [super initWithFrame:frameRect];
    if (self) {
        int bitmapByteCount;
        int bitmapBytesPerRow;

        bitmapBytesPerRow = (BitmapWidth * 4);
        bitmapByteCount = (bitmapBytesPerRow * BitmapHeight);
        BitmapMemory = mmap(0,
                            bitmapByteCount,
                            PROT_WRITE |
                            PROT_READ,
                            MAP_ANON |
                            MAP_PRIVATE,
                            -1,
                            0);
        //CMProfileRef prof;
        //CMGetSystemProfile(&prof);
        CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
        backBuffer_ = CGBitmapContextCreate(BitmapMemory, BitmapWidth, BitmapHeight, 8, bitmapBytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
        CGColorSpaceRelease(colorSpace);
        //CMCloseProfile(prof);
    }
    return self;
}



- (void)drawRect:(NSRect)dirtyRect {
    CGContextRef gctx = [[NSGraphicsContext currentContext] graphicsPort];
    CGRect myBoundingBox;
    myBoundingBox = CGRectMake(0, 0, 1024, 768);
    //RenderWeirdGradient(XOffset, YOffset);
    CGImageRef backImage = CGBitmapContextCreateImage(backBuffer_);
    CGContextDrawImage(gctx, myBoundingBox, backImage);
    CGImageRelease(backImage);
}


internal void RenderWeirdGradient(int BlueOffset, int GreenOffset) {
    int Width = BitmapWidth;
    int Height = BitmapHeight;

    int Pitch = Width*BytesPerPixel;
    uint8 *Row = (uint8 *)BitmapMemory;
    for(int Y = 0;
        Y < BitmapHeight;
        ++Y)
    {
        uint8 *Pixel = (uint8 *)Row;
        for(int X = 0;
            X < BitmapWidth;
            ++X)
        {
            *Pixel = 0;
            ++Pixel;

            *Pixel = (uint8)Y + XOffset;
            ++Pixel;

            *Pixel = (uint8)X + YOffset;
            ++Pixel;

            *Pixel = 255;
            ++Pixel;

        }

        Row += Pitch;
    }
}



@end


static void createWindow() {
    NSUInteger windowStyle = NSTitledWindowMask  | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask;

    NSRect screenRect = [[NSScreen mainScreen] frame];
    NSRect viewRect = NSMakeRect(0, 0, 1024, 768);
    NSRect windowRect = NSMakeRect(NSMidX(screenRect) - NSMidX(viewRect),
                                   NSMidY(screenRect) - NSMidY(viewRect),
                                   viewRect.size.width,
                                   viewRect.size.height);

    window = [[NSWindow alloc] initWithContentRect:windowRect
                                                    styleMask:windowStyle
                                                      backing:NSBackingStoreBuffered
                                                        defer:NO];

    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

    id menubar = [[NSMenu new] autorelease];
    id appMenuItem = [[NSMenuItem new] autorelease];
    [menubar addItem:appMenuItem];
    [NSApp setMainMenu:menubar];

    // Then we add the quit item to the menu. Fortunately the action is simple since terminate: is
    // already implemented in NSApplication and the NSApplication is always in the responder chain.
    id appMenu = [[NSMenu new] autorelease];
    id appName = [[NSProcessInfo processInfo] processName];
    id quitTitle = [@"Quit " stringByAppendingString:appName];
    id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle
                                                  action:@selector(terminate:) keyEquivalent:@"q"] autorelease];
    [appMenu addItem:quitMenuItem];
    [appMenuItem setSubmenu:appMenu];

    NSWindowController * windowController = [[NSWindowController alloc] initWithWindow:window];
    [windowController autorelease];

    //View
    view = [[[View alloc] initWithFrame:viewRect] autorelease];
    [window setContentView:view];

    //Window Delegate
    windowDelegate = [[WindowDelegate alloc] init];
    [window setDelegate:windowDelegate];

    [window setAcceptsMouseMovedEvents:YES];
    [window setDelegate:view];

    // Set app title
    [window setTitle:appName];

    // Add fullscreen button
    [window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
    [window makeKeyAndOrderFront:nil];
}

void initApp() {
    [NSApplication sharedApplication];

    appDelegate = [[AppDelegate alloc] init];
    [NSApp setDelegate:appDelegate];

    running = true;

    [NSApp finishLaunching];
}

void frame() {
    @autoreleasepool {
        NSEvent* ev;
        do {
            ev = [NSApp nextEventMatchingMask: NSAnyEventMask
                                    untilDate: nil
                                       inMode: NSDefaultRunLoopMode
                                      dequeue: YES];
            if (ev) {
                // handle events here
                [NSApp sendEvent: ev];
            }
        } while (ev);
    }
}

int main(int argc, const char * argv[])  {
    initApp();
    createWindow();
    while (running) {
        frame();
        RenderWeirdGradient(XOffset, YOffset);
        [view setNeedsDisplay:YES];
        XOffset++;
        YOffset++;
    }

    return (0);
}

这是应用程序到目前为止需要运行的所有代码。只需将其复制并粘贴到空的 Xcode 命令行项目中即可运行。

然而,当您在应用程序运行时检查硬件时,您会发现 CPU 几乎以 100% 的速度运行。我读到这个问题的原因是由于自定义运行循环,应用程序必须一直搜索新事件。

此外,由于循环不会将控制权交给委托对象,因此方法如- (BOOL)windowShouldClose:(id)sender不再工作了。

问题:

  1. 有没有一种更好的方法可以使用下面的样式实现自定义主应用程序循环,并且不会像我正在使用的那样浪费 CPU 时间?

    在跑步的时候) { //做东西 }

  2. 由于应用程序委托和窗口委托方法不再响应,如何通过按窗口的关闭按钮来终止应用程序?

我现在花了几个小时在网上搜索 Cocoa 中的自定义主运行循环,但只是遇到了多线程和对我没有帮助的东西。

您能推荐一些对我的情况有帮助的在线资源/书籍吗?我真的很想获得一些处理不寻常事物(例如自定义运行循环)的资源。


我知道这已经晚了两年了,但我在 Cocoa With Love 上发现了一篇文章,你可能会觉得有用。

https://www.cocoawithlove.com/2009/01/demystifying-nsapplication-by.html https://www.cocoawithlove.com/2009/01/demystifying-nsapplication-by.html

我尝试以这种方式实现主事件循环,查看了 CPU 使用率,它比我之前得到的更合理。我不完全知道为什么,但我会对此做更多研究。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

可可中的自定义主应用程序循环 的相关文章

  • UITableview Cell 异常 - '必须将自动调整大小掩码转换为约束才能具有 _setHostsLayoutEngine:YES

    我正在使用 UITableView CategoryCell cell tableView dequeueReusableCellWithIdentifier CellIdentifierLink 这是我收到错误的行 它在 IOS 7 中工
  • 如何在 iOS 中将 URL 添加到 Safari 的阅读列表?

    在我的 UIWebView 中 我想添加一个选项来将当前页面添加到 Safari 的阅读列表中 我知道这个功能的存在 因为 GMail 在长按链接时提供了它 但我找不到任何有关要使用的 URL 方案的信息 可能重复 如何从 iOS 以编程方
  • OS X:发送邮件到本地主机

    出于测试目的 我想将邮件发送到我的本地主机用户帐户而不是我的网络服务器 我不确定如何使用 mail app 执行此操作 任何帮助 将不胜感激 同义反复 OSX 确实有一个内置的 MTA SMTP 服务器 要打开它 您可以键入 sudo la
  • CIImage内存未释放

    我正在尝试拍摄一系列图像 混合当时的 X 图像并生成新图像 这是我必须完成此任务的代码 static func blendImages blendFrames Int blendMode CIImage BlendMode imagePat
  • Python中的MariaDB连接器无法连接到远程服务器

    我使用与远程 Mariadb 服务器的连接已有几个月了 今天 无法再通过 macOS 上的 python mariadb 模块和 mariadb 连接器建立连接 基本安装如下 brew install mariadb connector c
  • 查找 iPhone 上已安装应用程序的列表

    是否可以以编程方式查找我的 iOS 设备上安装的所有应用程序的名称 有没有可用的API 谢谢您的帮助 不可以 由于沙盒环境 iOS 应用程序无法访问其他应用程序的信息
  • 为什么 tkinter 在 Mac 上失败

    我在 Mac 上使用 tkinter 但是当我使用以下简单代码时 计算机将重新启动 import tkinter as tk window tk Tk 问题是什么 谢谢你 Mac 莫哈韦沙漠 版本 10 14 6 tkinter 版本 8
  • UILabel 文本的大纲

    如何向白色 UILabel 文本添加黑色轮廓 一种选择是设置阴影 这可能不完全是您想要的 但可以达到类似的效果 您可以手动调整偏移量 UILabel myLabel lbl shadowColor UIColor whiteColor lb
  • 检查包含 URL 的字符串“http://”

    我正在尝试检查用户输入的 URL 但我正在与一些错误和警告作斗争 BOOL textFieldShouldReturn UITextField textField check http NSString check textField te
  • Objective-C 属性的默认属性是什么?

    当您未在 Objective C 中列出任何属性时 属性的默认属性是什么 例如 如果我这样写 property float value 默认值是什么 比如它是只读的 它是否保留 等等 默认 隐式值为atomic readwrite and
  • iOS 中特定字符串的 SHA1

    根据我的要求 输入字符串必须转换为字节值 string 的每个字符都是 16 位值 必须转换为低 8 位 然后在字节数组上计算 Sha1 生成的 SHA 1 将转换为 40 个字符的字符串 我知道如何将字符串转换为 SHA1 但其余部分对我
  • iOS) 照片扩展无法保存更改问题

    我正在制作照片扩展 但是当我尝试保存更改时 点击 完成 按钮 警报消息显示 无法保存更改 发生错误 节省的同时 请稍后再试 这是我的代码finishContentEditingWithCompletionHandler completion
  • 在 iOS8.3 上显示警报视图时不必要地触发 iOS 键盘通知

    我们正在观察 iOS 8 3 上键盘将显示和隐藏通知的异常行为 视图控制器 监听键盘通知 有一个文本字段 单击并点击提交按钮后 该方法首先从文本字段中退出第一响应者 并显示一条警报以通知警告 一切正常 它会关闭键盘并按预期显示警报 也调用
  • Cocoa 我可以隐藏/显示 NSTextField / NSSecureTextField

    有没有办法在 Cocoa 中打开和关闭 secureTextField 操作系统 我希望用户可以选择查看他们的密码 在 iOS 中 我可以执行类似 textField setSecureTextEntry YES 的操作 我找到了 secu
  • 更新 OSX 命令行工具 6.3 后缺少 C++ 标头 <__debug>

    从 App Store 更新到 Command Line Tools 6 3 后 程序包括
  • NSRunningApplication - 终止

    我将如何使用NSRunningApplication 我有与启动应用程序相反的东西 NSWorkspace sharedWorkspace launchApplication appName 但我想关闭一个 当我调试代码时出现错误NSRun
  • Cocoa 应用程序未在 High Sierra 上加载视图或运行代码

    我在 Mac AppStore 上有一个应用程序 许多用户最近写信说它无法在 High Sierra 上运行 可能是 10 13 6 很难从中提取具体信息 我设法在朋友的设备上重现了该问题 但是我无法使用该设备通过 Xcode 等进行构建
  • 使用 Objective C 将 html 字符串插入 sqlite 数据库

    我正在使用下面的代码片段将 html 字符串插入 sqlite 数据库 我的代码工作正常 但是当我检索相同的 html 字符串并在 Web 视图中显示时 它不会呈现 一些数据正在被修改 任何人都可以帮助如何插入长 html 字符串存入数据库
  • 为什么 NSOrderedSet 不继承 NSSet?

    当然 有序集是集合的更具体的情况 那么为什么NSOrderedSet继承自NSObject而不是NSSet 我通过了界面NSSet你是对的 有序集似乎满足里氏替换原则 http en wikipedia org wiki Liskov su
  • 如何在 UIButton 中创建边框?

    我在名为 addButton 的应用程序中使用自定义按钮 我想用白色边框它 如何在自定义按钮周围获得白色边框 您可以通过访问按钮的图层属性来设置 CALayer 上的边框属性 首先 添加石英 import

随机推荐

  • 如何在组件内部调用组件 [OctoberCMS]

    I want to call a component inside a component with a variable like this 这是default html gt 的代码 div class container div cl
  • 如何注册一个类以在 Qt 中的 QWebChannel 信号中使用它

    我使用 QT 5 和 WebChannel 与 HTML 页面进行通信 我成功地能够传达文本和字符串 不过我想传达一些点数据 官方文档说 不需要手动消息传递和数据序列化 http doc qt io qt 5 qwebchannel htm
  • MVVM 中的后台线程进度通知?

    如何修改 MVVM 视图模型Progress在后台线程上完成的工作的属性 我正在创建一个 MVVM 应用程序 它在后台线程上执行任务 使用Task Factory StartNew and Parallel ForEach 我在用本文 ht
  • AT+CUSD 无法在华为 e3131a 调制解调器上工作

    我试图发送 at 命令以在 huawei e3131a 调制解调器上获得平衡 但无论我使用什么配置 GSM IRA UCS2 我总是收到 Ok 作为答案 我还尝试更改操作员代码 123 到许多格式 如十六进制 PDU 简单字符串 但无法获得
  • 使 in 子句将所有项目与任何替代项相匹配?

    我有一张桌子hotel hotelid hotelname etc 和另一张桌子facilities facilityid facilityname 这两个表通过 table 链接hotel to facilities map hoteli
  • 使用从 bash 中的文件读取的数组并行化 while 循环

    我在 Bash 中有一个 while 循环 处理如下 while IFS t read r a line do myprogram line 0 line 1 line 0 vs line 1 result done lt fileinpu
  • 我想禁用特定航空窗口上的阴影效果

    我想禁用特定航空窗口上的阴影效果 我所拥有的只是该窗口的 HWND 这可能吗 阴影由操作系统当前使用的主题定义 您不能仅针对一个窗口禁用它 您可以更改主题并禁用阴影 但这将是系统范围内的更改 而不是特定于某个窗口 就您而言 最好的方法之一是
  • 从 SSIS 执行 SQL 任务返回整数值

    我正在使用 SQL Server 2005 Business Intelligence Studio 并努力从一个非常简单的执行 SQL 任务返回一个整数值 为了一个非常简单的测试 我将 SQL 语句编写为 Select 35 As Tot
  • NSManagedObjectModel - 动态创建模型

    谁能给我指点一下在 Xcode 中动态构建核心数据模型的教程吗 我发现的所有教程都是基于静态设计 但苹果文档说可以以编程方式构建模型 遗憾的是 苹果文档集中没有相关示例 你必须初始化一个NSManagedObjectModel 然后为模型中
  • Bash:无限睡眠(无限阻塞)

    I use startx启动 X 它将评估我的 xinitrc In my xinitrc我使用启动窗口管理器 usr bin mywm 现在 如果我终止我的 WM 为了测试其他 WM X 也会终止 因为 xinitrc脚本到达 EOF 所
  • 如何让 ServiceStack 身份验证发挥作用? (使用 iPhone 客户端)

    我们聘请了一名承包商 他正在为我们编写 iPhone 应用程序 我开始使用 ServiceStack 为其编写后端服务 我在一般授权方面遇到了困难 使用什么样的授权以及如何实现它 我对 ServiceStack HTTP 和授权不太了解 还
  • JFormattedTextField 中严格的 24 小时时间

    我正在尝试创建一个仅接受 24 小时时间的 JFormattedTextField 我非常接近解决方案 但有一种情况以下代码示例不起作用 如果输入时间 222 并从字段中更改焦点 时间将更正为 2202 我希望它只接受完整的 4 位数 24
  • 为 SQL Server 中的特定记录生成脚本

    这可能是一个有限但有价值的场景 我有一个 SQL Server 2008 数据库 其中有一个包含数百万条记录的表 一些记录似乎存在间歇性问题 我正在尝试重现该问题 为了做到这一点 我终于获得了违规记录的 ID 我想在我的 PROD 数据库中
  • 如何从 C# 代码重新启用 Gmail 中的弹出功能?

    我有一个从 Gmail 下载邮件的程序 我选择了单选按钮 为所有邮件启用 POP 甚至是已下载的邮件 下载邮件后 我的 Gmail 将上述状态更改为 对自当前日期以来到达的所有邮件启用 POP 我没有物理更改单选按钮 但它似乎自动将其设置为
  • 如何在剑道网格中加载大量数据

    网页方法
  • calloc(4, 6) 与 calloc(6, 4) 相同吗?

    我是一名初学者 C 程序员 我认为情况会如此 但如果可能的话希望得到一些肯定 如果它们是相同的 为什么不只取一个参数呢 之间没有真正的区别calloc a b and calloc b a 尽管如此 它们都分配相同数量的空间并适当填充它 元
  • 嵌套名称说明符

    我有一个类似的代码 namespace mymap template
  • 可拖动元素的包含

    如何定义可拖动对象的包含区域以使其可拖动到其父元素之外 我有两个可放置的容器 其中有可拖动的 div 我想在容器之间拖动包含的 div 但是 div 落在父容器的边框下方 而不是穿过父容器的边框 如果我设置了非常高的 z 索引 我只能让 d
  • 如何在 HTML5 Canvas 中使用动态旋转值绘制水印?

    我正在使用 HTML5 我正在尝试使用文本在图像上绘制水印 我有以下代码 div style width 612px height 792px div
  • 可可中的自定义主应用程序循环

    我一直在关注 Handmade Hero 项目 其中 Casey Muratori 从头开始 创建了一个完整的游戏引擎 而不使用库 该引擎具有高度可移植性 因为它呈现自己的位图 然后平台特定的代码将其绘制到屏幕上 在 Windows 下 通