[ObjC翻译]用Objective-C++在iOS应用程序中使用C和C++

729 阅读5分钟

本文由 简悦SimpRead 转码,原文地址 www.sitepoint.com

在介绍了在Android应用程序中使用C和C++之后,Rico Zuñiga现在看看在iOS中使用这些语言的情况。......

在我的上一篇教程中,我讨论了如何使用本地开发工具包在C或C++中开发Android应用。在本教程中,我将介绍如何在iOS中使用C或C++和Objective-C。与Android需要一个特殊的API(NDK)来支持本地开发不同,iOS默认支持。C或C++的开发在iOS中更加直接,因为有一个叫做 "Objective-C++"的功能。我将讨论什么是Objective-C++,它的局限性以及它如何用于构建iOS应用程序。

什么是Objective-C++?

Objective-C++听起来像是一种新的编程语言,但它不是。它是两种语言的组合,Objective-C和C++。苹果公司提供Objective-C++作为一种方便的机制来混合Objective-C代码和C++代码。

Objective-C接近于C语言,但有面向对象的功能,作为C语言的一个薄层实现。它是C语言的一个严格的超集,这使得任何C语言代码都是有效的Objective-C程序。

尽管Swift现在是开发iOS应用程序的推荐语言,但仍有很好的理由使用C、C++和Objective-C等旧语言。尽管Swift迅速崛起,Objective-C仍然是iOS上的主流语言,因为现有的应用程序和库的数量已经用它创建。

使用Objective-C的一个原因是将为其他平台编写的现有C/C++程序移植到iOS。使用C或C++开发跨平台的应用程序是可能的,只要仔细规划。尽管Swift是开源的,但它还没有完全支持其他平台。另一个用例是能够利用已有的本地代码库。这是在iOS应用中仍然使用C/C++/Objective-C的最重要原因之一。

使用Objective-C++

本教程的最终项目可以在[GitHub]上找到(github.com/sitepoint-e…

###创建项目

打开Xcode并选择_创建一个新的Xcode项目_。

在模板选择界面,从iOS应用程序标签中选择_Single View Application_并点击_Next_。

在项目选项屏幕中,将产品命名为_HelloCpp_。以反向域名的方式输入你的组织和组织标识符。

因为它不是一种真正的语言,所以没有选项可以创建一个Objective-C++项目。可用的是Objective-C或Swift。对于这个项目,选择Objective-C。其他选项保持不变,然后点击_Next_,选择一个文件夹来保存项目。

C++

是时候添加一些C++代码了。如果这是你第一次使用C++,请查看关于该语言的本教程。看看左边的_项目导航_窗格。大多数文件都以_.h_或_.m_结尾。那些以_.h_结尾的是头文件,而那些以_.m_结尾的是Objective-C源文件。

创建一个C++类,将从Objective-C文件中调用。使用_File -> New -> File...菜单项或按_⌘ + N_创建一个新文件。在出现的文件模板窗口中,选择_iOS -> Source -> C++ File_并点击_Next

将文件命名为_Greeting_,保持勾选_同时创建一个头文件_的选项,然后点击_Next_。将该文件保存在_HelloCpp_文件夹中。

该项目现在的结构应该如下所示。请随意拖动文件以改善_Project Navigator_中的安排。

打开_Greeting.hpp_,在include <stdio.h>#endif /* Greeting_hpp */行之间添加以下代码。

#include <string

class Greeting {
    std::string greeting;
public:
    问候语()。
    std::string greet();
};

在_Greeting.cpp_中定义这些方法,在 "include "Greeting.hpp "行后添加以下代码。

问候语::问候语() {
    greeting = "Hello C++!";
}

std::string Greeting::greet() {
    返回greeting。
}

这是简单的代码,它创建了一个名为Greeting的类,有一个名为greet()的方法,返回一个字符串值。

Objective-C with C++

现在你已经添加了简单的C++问候类,试着从Objective-C中调用它。打开_ViewController.m_,导入_Greeting.hpp_头文件。

#import "ViewController.h"
#import "Greeting.hpp"
...

在ViewController的@interface块中声明一个Greeting类型的变量。

@interface ViewController ()
{
    问候语 greeting;
}
@结束

如果启用了_Show live issues_选项,在添加上一行代码后,会立即出现一个错误,即未知类型名称'Greeting'。为了解决这个问题,将_ViewController.m_重命名为_ViewController.mm_。这个简单的命名规则告诉Xcode,ViewController想要混合Objective-C和C++。重命名文件后,错误应该消失。

让我们通过添加一个按钮来使这个应用程序更具互动性。从_Project Navigator_中选择_Main.storyboard_以显示View Controller场景。从对象库中拖动一个按钮到视图的中心,如下图所示。将文本改为_Tap Me!_。

创建一个UIButton出口,指向最近创建的按钮。当仍然在_Main.storyboard_屏幕上时,通过在工具栏上切换助理编辑器来打开它。按键盘上的_control_键,从按钮上拖出一个连接器到 "问候 "变量下面的一行。将这个出口命名为_helloButton_。

打开_ViewController.h_,在@interface@end之间添加以下IBAction方法。

- (IBAction)showGreeting;

在_ViewController.mm_中定义这个方法,在- (void)didReceiveMemoryWarning函数之后和@end之前插入以下代码。

- (IBAction)showGreeting {

    NSString* newTitle = [NSString stringWithCString:greeting.greet().c_str() encoding:[NSString defaultCStringEncoding]] 。

    [helloButton setTitle:newTitle forState:UIControlStateNormal]。
}

这个方法调用C++类Greeting中定义的greet()方法,并使用它返回的字符串值来替换_Tap Me!_按钮的标题。使用同样的_control + drag_技术将按钮连接到这个动作。回到_Main.storyboard_屏幕,通过工具栏打开助手编辑器,然后_control + drag_从按钮到- (IBAction)showGreeting方法主体的连接器。- (IBAction)showGreeting方法左边的空心小圆圈应该被激活/填满,表明_Tap Me!_按钮现在已经连接到该动作。

建立并运行该应用程序。注意到按钮在模拟器上出现偏离中心的情况。通过使用_Control + drag_技术启用自动布局约束来解决这个问题。将按钮连接到它的容器,并启用垂直和水平居中。再次运行该应用程序以看到改进。

限制条件

Objective-C++实际上并没有将Objective-C与C++的功能合并。这意味着,Objective-C类不会有C++可用的功能,反之亦然。下面的代码例子说明了这些限制。

使用Objective-C语法调用一个C++对象将不工作

std::string greet = [greeting greet]; 

不能给Objective-C对象添加构造函数或析构函数

@interface ViewController ()
{
    问候语greeting。
    IBOutlet UIButton *helloButton;
    ViewController()。
    ~ViewController(); 
}
@end

关键字thisself不能互换使用

std::string greet = self->greeting.greet(); 
std::string greet2 = this->greeting.greet()。

一个C++类不能继承一个Objective-C类

#include <stdio.h>
#include <string
#include "ViewController.h"

class Greeting: public ViewController { 
    std::string greeting;
公共的。
    问候()。
    std::string greet();
};

一个Objective-C类不能继承自C++类

#import "Greeting.hpp"

@interface Goodbye : Greeting 

@结束

异常处理在混合使用Objective-C和C++时也不完全支持

在Objective-C代码中抛出的异常不能被C++代码捕获,而在C++代码中抛出的异常不能被Objective-C代码捕获。

double divide(int dividend, int divisor) {
    if ( divisor == 0 ) {
        throw "Cannot divide by zero!"; 
    }

    返回(股息/除数)。
}

重复使用库

重用现有的C/C++库的能力是考虑本地语言的最重要用例之一,在iOS中这是一个简单的过程。虽然Android仍然需要一个单独的NDK,但iOS已经支持C和C++。

SDL

Android NDK教程一样,我们将在这个例子中使用SDL。Simple DirectMedia Layer](www.libsdl.org/)是一个开源的硬件抽象…

项目设置

首先从下载页面下载SDL的源代码,或者用Mercurial repo克隆。

hg clone http://hg.libsdl.org/SDL

下载或克隆完成后,在Xcode中创建一个新的_Single View Application_项目。将其命名为_HelloSDL_,语言设置为Objective-C。

你将从头开始,所以在_项目导航器_中,选择以下高亮的文件并将它们移到垃圾桶中。

从_Info.plist_文件中删除以下键。

使用_File -> Add Files to Hello SDL...菜单项将SDL库项目添加到_HelloSDL。导航到下载或克隆的SDL文件夹,进入_Xcode-iOS/SDL/,然后选择_SDL.xcodeproj

在_Project Navigator_中选择主_HelloSDL_项目,在Targets下选择_HelloSDL_。向下滚动到_Linked Frameworks and Libraries_部分。

点击_+_按钮,手动添加_libSDL2.a_和下列框架。

  • AudioToolbox.framework
  • CoreAudio.framework
  • CoreGraphics.framework
  • CoreMotion.framework
  • Foundation.framework
  • GameController.framework
  • OpenGLES.framework
  • QuartzCore.framework
  • UIKit.framework

使用_Command+Click_来多重选择框架。通过选择新添加的框架并使用_New Group from Selection_上下文菜单项对它们进行分组来整理_Project Navigator_。

在项目中添加一个_main.c_文件。不需要为这个文件创建头文件,所以不要选中_Also create a header file_框。

我们将从_SDL/Xcode-iOS/Template/SDL iOS Application/main.c_文件中重新使用Holmes Futrell的这段示例代码。

#include "SDL.h"
#include <time.h

#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 480

int
randomInt(int min, int max)
{
    返回 min + rand() % (max - min + 1)。
}

空白
render(SDL_Renderer *renderer)
{

    Uint8 r, g, b;

    
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer)。

    
    SDL_Rect rect;
    rect.w = randomInt(64, 128);
    rect.h = randomInt(64, 128);
    rect.x = randomInt(0, SCREEN_WIDTH);
    rect.y = randomInt(0, SCREEN_HEIGHT);

    
    r = randomInt(50, 255);
    g = randomInt(50, 255);
    b = randomInt(50, 255);
    SDL_SetRenderDrawColor(renderer, r, g, b, 255)。

    
    SDL_RenderFillRect(renderer, &rect)。

    
    SDL_RenderPresent(renderer)。
}

int
main(int argc, char *argv[] )
{

    SDL_Window *window;
    SDL_Renderer *renderer;
    int done;
    SDL_Event事件。

    
    如果(SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("Could not initialize SDL\n")。
        返回1。
    }

    
    srand(time(NULL))。

    
    window =
        SDL_CreateWindow(NULL, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
                         sdl_window_opengl)。
    if (!window) {
        printf("Could not initialize Window/n")。
        返回1。
    }

    renderer = SDL_CreateRenderer(window, -1, 0);
    if (!renderer) {
        printf("Could not create renderer/n");
        返回1。
    }

    
    done = 0;
    while (!done) {
        while (SDL_PollEvent(&event)) {
            如果(event.type == SDL_QUIT) {
                done = 1;
            }
        }
        render(renderer);
        SDL_Delay(1);
    }

    
    SDL_Quit()。

    返回0。
}

这段代码在屏幕的随机区域显示随机颜色的矩形。把这段代码复制到_main.c_文件中。

最后,将_User Header Search Paths_属性设置为SDL头文件所在的文件夹。最简单的方法是创建一个符号链接,指向HelloSDL项目中的SDL文件夹,并将_User Header Search Paths_属性设置为_SDL/include/_。

确保_HelloSDL_是工具栏中的活动方案,然后构建并运行该项目以看到跳舞的矩形。

总结

正如你所看到的,通过使用Objective-C++,在iOS中开发C和C++是很简单的。如果你以前一直用C或C++编程,那么现在更容易过渡到iOS开发并利用你现有的技能。最重要的是,你可以利用现有的C/C++库,如强大的SDL,只需最小的配置。

我希望在下面的评论中听到你对使用Objective-C++的经验和意见。


www.deepl.com 翻译