Objective-CからC++コードを正常に呼び出すことができた方のために、私に教えていただけませんか?
これ link は、彼の記事で説明している手法を使用してC++コードをラップする必要があることを示しています。見た目は良さそうですが、まだ問題があります。
この link は、C++クラスを呼び出すObjective-Cクラスが.mm(Objective-C++)クラスに変換されている限り、2つはうまく連携するはずであることを示しています。
これらのアプローチのそれぞれは、私がメソッド呼び出しを追加しようとした瞬間に私を悲しませています。誰かが、「Hello」部分にObjective-Cを使用し、「World」部分にObjective-C++クラスを中央に持つC++クラスを使用する単純なHelloWorldiOSアプリのコードを教えてください。それとも私はまだ全体の概念が間違っていますか?
基本的に、拡張子が.mmのObjCクラスを呼び出す拡張子が.mmのObjCクラスが必要です。 2つ目は、C++ラッパークラスとして使用されます。ラッパークラスは、実際の.cppクラスを呼び出します。少し注意が必要なので、詳細なコードをいくつか紹介します。プロジェクトの概要は次のとおりです。
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;
}
このコードは完璧ではありません!名前空間テストの認識に問題があります。できれば更新します。
別の(考案された)もの:
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」はそれほど明白ではなく、混乱を引き起こす可能性があります。
要求に応じて;例:
#import <Foundation/Foundation.h>
#import <vector>
#import <string>
int main(int argc, const char **argv) {
std::vector<std::string> v;
v.Push_back("Hello");
v.Push_back("World");
for (std::string s : v)
NSLog(@"%s", s.c_str());
return 0;
}
$ clang -std=c++11 -stdlib=libc++ -o callcpp callcpp.mm -framework Foundation -lc++
$ ./callcpp
2013-10-07 17:16:13.725 callcpp[37710:707] Hello
2013-10-07 17:16:13.726 callcpp[37710:707] World