从 Objective-C 调用 C++

问题描述 投票:0回答:5

对于那些已经成功从 Objective-C 调用 C++ 代码的人,请赐教一下吗?

链接表示您需要使用他在文章中描述的技术来包装 C++ 代码。看起来不错,但我还是有问题。

这个link说只要调用C++类的Objective-C类已经转换为.mm(Objective-C++)类,那么两者应该可以很好地协同工作。

当我尝试添加方法调用时,这些方法中的每一种都让我感到悲伤。有人能给我一个简单的 Hello World iOS 应用程序的代码吗?该应用程序使用 Objective-C 作为“Hello”部分,使用 C++ 类作为“World”部分,中间有一个 Objective-C++ 类?还是我的整个概念仍然错误?

c++ ios objective-c objective-c++
5个回答
27
投票

本质上,您需要一个具有 .mm 扩展名的 ObjC 类来调用具有 .mm 扩展名的 ObjC 类。 第二个将用作 C++ 包装类。 包装类将调用您实际的 .cpp 类。 这有点棘手,所以我将给您一些详细的代码。 以下是该项目的概述:

enter image description here

在您的 ObjC 代码 (ViewController) 中,您将调用 CplusplusMMClass

- (IBAction)buttonPushed:(UIButton *)sender {
    self.mmclass = [[CplusplusMMClass alloc]init];  // bad practice; but showing code
    NSString *str = [self.mmclass fetchStringFromCplusplus];
    [self populateLabel:str];
}

这是 CplusplusMMClass .h 和 .mm

#import <Foundation/Foundation.h>
#import "WrapperClass.h"

@interface CplusplusMMClass : NSObject
@end

@interface CplusplusMMClass()
@property (nonatomic, strong) WrapperClass *wrapper;
- (NSString*)fetchStringFromCplusplus;
@end

#import "CplusplusMMClass.h"
#import "WrapperClass.h"

@implementation CplusplusMMClass

- (NSString*)fetchStringFromCplusplus {
    self.wrapper = [[WrapperClass alloc] init];
    NSString * result = [self.wrapper getHelloString];
    return result;
}

@end

这里是 WrapperClass .h 和 .mm

#ifndef HEADERFILE_H
#define HEADERFILE_H

#import <Foundation/Foundation.h>

#if __cplusplus

#include "PureCplusplusClass.h"

@interface WrapperClass : NSObject
@end

@interface WrapperClass ()
- (NSString *)getHelloString;
@end


#endif
#endif

#import "WrapperClass.h"

#include "WrapperClass.h"
#include "PureCplusplusClass.h"

using namespace test;

@interface WrapperClass ()
@property (nonatomic) HelloTest helloTest;
@end

@implementation WrapperClass

- (NSString *)getHelloString {
    self.helloTest = *(new HelloTest);
    std::string str = self.helloTest.getHelloString();
    NSString* result = [[NSString alloc] initWithUTF8String:str.c_str()];
    return result;
}

@end

这是 PureCplusplusClass .h 和 .cpp

#ifndef __HelloWorld__PureCplusplusClass__
#define __HelloWorld__PureCplusplusClass__

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

using namespace std;

namespace test {
    class HelloTest
    {
    public:
        std::string getHelloString();
    };
}

#endif /* defined(__HelloWorld__PureCplusplusClass__) */

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

std::string test::HelloTest::getHelloString() {
    std::string outString = "Hello World";
    return outString;
}

这段代码并不完美! 我在识别命名空间测试时遇到问题。 我会尽可能更新。

但这应该能让你到达那里!!!!


2
投票

另一个(人为的):

使用 C++ 类作为 ivar:

文件 Foo.h

#import <Foundation/Foundation.h> 

@interface Foo : NSObject
@property (nonatomic, readonly) NSString* what;
@end

文件:Foo.mm

#import "Foo.h"
#include <string>

@implementation Foo {
    std::string _string;  // C++ class must have a default c-tor
}

- (id)init
{
    self = [super init];
    if (self) {
        _string = "Hello, World!"
    }
    return self;
}

- (NSString*) what {
    NSString* result = [[NSString alloc] initWithBytes:_string.data()
                                                length:_string.size() 
                                              encoding:NSUTF8StringEncoding];
    return result;
}

@end

注:

可执行文件可能需要显式链接 C++ 库,例如通过向“其他链接器标志”添加一个附加标志:

-lc++

或者,可以将

main.m
文件重命名为
main.mm

后者在选择“正确”库方面更加稳健,因为工具链会自行完成此操作。但也许,对于检查该项目的其他人来说,重命名的“main.m”可能并不那么明显,并且可能会引起混乱。


0
投票

我在 xcode 12.4 中遇到了这种情况,需要在 Objective-C 项目中使用现有的 C++ 类“CppModule”。这就是我所做的。

  1. 第一个问题是 CppModule.hpp 中的 #include 给出了编译器错误:找不到“string”文件。通过将 .hpp 文件内容包装在
  2. 中修复了该问题
#if defined __cplusplus
  declarations
#endif
  1. 然后 string var 声明又给出了另一个编译器错误:Unknown type name 'string';您的意思是“std::string”吗?通过以下方式解决了这个问题:
#include <string> 
using namespace std;
  1. C++ CppModule.cpp、CppModule.hpp 包含文件、调用的 Objective-C module.m 及其 module.h 文件必须全部设置为“Objective-C++ Source”类型,使用 xcode 的 Inspector(右上角)在编辑器窗口中)。将 module.m 重命名为 module.mm 还会将类型设置为“Objective-C++ Source”(xcode 12.4)。也许使用 .mm 很好,提醒一下它调用 C++。

在 module.h 文件中包含 C++ 头文件:

#include < CppModule.hpp>
  1. (对我来说)奇怪的是,在 module.h 文件中,“CppModule”不被识别为已知类型,因此您不能在 module.h 中声明该类型的变量或属性,但在 module.m(m) 中文件它是已知类型。在 module.mm 文件中,在 @implementation 之后添加:
static CppModule *module_cpp;
  1. 现在您可以,例如在 module.mm 的 init 中,调用 C++ 模块的初始化程序,例如:
module_cpp = new CppModule(parameters);

并且 C++ 模块仍然可以通过静态 module_cpp *指针进行访问。

  1. 在您的 Objective-C 方法中调用 module.cpp 的方法(示例):
CppModule::Result r = module_cpp->CppMethod();

看起来工作绝对没问题!

如果有人能解释4中的奇怪之处。我将不胜感激。

我需要的模块只是做一些复杂的(数字)计算,我不想将该代码转换为 Objective-C。


0
投票

最近写了一篇关于此的博客文章......

https://jm79blog.wordpress.com/2024/08/02/using-c-in-ios-swiftui/

包含 GitHub 演示:)


-1
投票

Objective c 的 IOS 网上银行示例

- (IBAction)Button:(id)sender {

    NSMutableArray *userdata=[[NSMutableArray alloc]initWithObjects:@"Name",@"CreditcardNumber",@"Pinnumber",@"Active", nil]; // arrkey = userdata.

    NSMutableArray *Yogesh=[[NSMutableArray alloc]initWithObjects:@"Yogesh",@"908380637367",@"5656",@"yes", nil];
    NSMutableArray *sabari=[[NSMutableArray alloc]initWithObjects:@"Sabari",@"7635298721",@"6543",@"no",nil];
    NSMutableArray *rajesh=[[NSMutableArray alloc]initWithObjects:@"rajesh",@"8373197272",@"8765",@"yes",nil];
    NSMutableArray *Ramya =[[NSMutableArray alloc]initWithObjects:@"Ramya ",@"123456",@"9898",@"No",nil];
    NSMutableDictionary * dic= [[NSMutableDictionary alloc]initWithObjects:Yogesh forKeys:userdata];
    NSMutableDictionary * dic1=[[NSMutableDictionary alloc]initWithObjects:sabari forKeys:userdata];
    NSMutableDictionary * dic2=[[NSMutableDictionary alloc]initWithObjects:rajesh forKeys:userdata];
    NSMutableDictionary * dic3=[[NSMutableDictionary alloc]initWithObjects:Ramya  forKeys:userdata];
    /* NSLog(@"%@", dic);
     NSLog(@"%@", dic1);
     NSLog(@"%@", dic2);*/

    NSMutableArray * arraylist=[[NSMutableArray alloc]initWithObjects:dic,dic1,dic2,dic3, nil];
    NSLog(@"Array = %@", arraylist);
    NSLog(@"user entered value %d", _ccNumber.text.intValue);
    NSLog(@"pin number %d ",_pin.text.intValue);

    for(int i = 0; i< [arraylist count]; i++){
    
        NSMutableDictionary *dictionary= arraylist[i];
            
        // NSLog(@"userdata is [%d] %@",i,[dictionary objectForKey:@"Pinnumber"]);
    
        NSInteger a;
        NSInteger vx;
        NSString *b;
        NSString *str;
        a = (self.ccNumber.text.integerValue);
        vx = (self.pin.text.integerValue);
        b = ([dictionary objectForKey:@"CreditcardNumber"]);
        str = ([dictionary objectForKey:@"Pinnumber"]);
        NSInteger c = [b integerValue];
        NSInteger d = [str integerValue];
        if(a == c && vx == d){
            NSLog(@" user data is [%d] Name: %@",i,[dictionary objectForKey:@"Name"]);
            NSLog(@" user data is [%d] Card Number: %@",i,[dictionary objectForKey:@"CreditcardNumber"]);
            NSLog(@" user data is [%d] Pin Number :%@",i,[dictionary objectForKey:@"Pinnumber"]);
            NSLog(@" user data is [%d] Active: %@",i,[dictionary objectForKey:@"Active"]);
        }else{
        
            NSString *DataStatus= @"Invalid Card Number";
        
            self.dataStatusLbl.text = DataStatus;
        
            NSLog(@"%@",DataStatus);
        }
    }
}
@end
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.