swift

Swift, Objective-C, C++ 같이 사용하기

j2kb 2020. 4. 25. 12:10
반응형

 

iOS 앱을 만들 때 모든 것을 다 Swift로 짜면 좋으련만 프로젝트를 진행하다보면 그렇지 못할 경우가 간혹 생깁니다.

Web RTC를 쓴다던지 게임 엔진을 같이 사용해야 한다던지 등등..

 

회사에서 cocos2dx 게임엔진이 메탈을 지원하기 때문에 cocos2dx를 swift와 같이 사용할 일이 생겼습니다. 

이 때 처음으로 C++ 소스를 Swift와 같이 사용하게 되며 공부를 하였는데 어떻게 사용할 수 있는지 그 방법을 다시 정리해보았습니다.

 

결론을 말씀드리면 C++는 Objective C++로 Wrapping해서 Swift에서도 쓸 수 있습니다.

 

Photo credit: Cecilia Humlelu

Swift는 Objective C(++)과 C는 직접 상호동작이 가능하지만 C++은 그렇지 못한 걸 알 수 있습니다.

 

 

아래 순서대로 진행할 생각입니다.

1. Xcode 프로젝트 Swift로 생성

2. C++ 파일 작성

3. Objective C++ Wrapper만들기

4. 브릿지 헤더에 만든 Objective C++의 헤더 추가하기

5. Swift에서 호출하기

 

1. Xcode 프로젝트 Swift로 생성

편한 이름으로 언어는 Swift를 선택하시고 iOS 앱 프로젝트를 생성해주세요. 저는 CppTest로 하였습니다.

 

 

2. C++ 파일 작성

[File] -> [New] -> [File]을 눌러(혹은 ⌘N) 새로운 C++ source file을 만들어주세요. 

생성 시 Also create a header file을 체크하고 만들어주세요. 저는 MyCpp로 하였습니다.

그러면 Bridge header를 만들 것인지 묻습니다. 만들어주세요

브릿지 헤더를 만듭니다

다 만들고 나면 아래와 같이 파일들이 생성될 것입니다.

C++ 파일 생성

 

*.hpp 파일을 열고 아래와 같이 입력해주세요.

// MyCpp.hpp

#include <string>
#include <iostream>

class MyCpp {
public:
    MyCpp();							// 생성자
    MyCpp(const std::string &text);				// 변수를 입력 받는 생성자
    ~MyCpp();							// 소멸자(Destructor)

public:
    void sayHello();						// Hello world를 출력하는 함수

    void setText(const std::string &text);			// m_text의 getter & setter
    const std::string &getText();
    
    void setNumber(const int number);				// m_number의 getter & setter
    int getNumber();

private:
    std::string m_text;						// 문자열 변수
    int m_number;						// 정수값 변수
};

 

 

 

*.cpp 파일을 열고 아래와 같이 입력해주세요.

//  MyCpp.cpp


#include "MyCpp.hpp"

MyCpp::MyCpp():m_text() {}
MyCpp::MyCpp(const std::string &text): m_text(text) {}
MyCpp::~MyCpp() {}

void MyCpp::sayHello()
{
    std::cout << "Hello world!" << std::endl;
    
}

void MyCpp::setText(const std::string &text)
{
    m_text = text;
}
const std::string &MyCpp::getText()
{
    return m_text;
}

void MyCpp::setNumber(const int number)
{
    m_number = number;
}

int MyCpp::getNumber()
{
    return m_number;
}

 

설명이 필요없는 아주 기본적인 각각 문자열과 정수값을 설정하고 반환하는 함수들입니다.

 

3. Objective C++ Wrapper만들기

새로운 objective-c 파일을 만들어주세요. 그리고 확장자를 .mm으로 바꿉니다. 저는 이름을 CWrapper.mm로 하였습니다.

방금 만든 파일의 헤더(header)도 만들어주세요. 제 파일은 CWrapper.h입니다.

Objective-C++을 생성하고 나서의 모습입니다. 아래쪽에 *.mm과 *.h가 하나씩 추가되었습니다.

 

*.h를 작성해 주세요

//  CWrapper.h

#import <Foundation/Foundation.h>

@interface CWrapper : NSObject
- (instancetype)initWithText:(NSString*)text;
- (void)helloWorld;

- (void)setText:(NSString*)text;
- (NSString*)getText;

- (void)setNumber:(int)number;
- (int)getNumber;
@end

 

C++에 있던 것과 마찬가지로 문자열을 입력받는 상속자와 문자열, 정수값을 설정하고 반환하는 함수들을 선언하였습니다.

 

이제 *.mm을 작성해 주세요.

만약 복붙이 아니라 직접 입력을 하신다면 헤더 파일을 만들어서 자동완성에 함수가 뜨는 것을 볼 수 있습니다.

#import "CWrapper.h"
#include "MyCpp.hpp"

@interface CWrapper()
@property MyCpp *cppItem;
@end
@implementation CWrapper
- (instancetype)init
{
    self = [super init];
    self.cppItem = new MyCpp();
    return self;
}
- (instancetype)initWithText:(NSString*)text
{
    self = [super init];
    self.cppItem = new MyCpp(std::string([text cStringUsingEncoding:NSUTF8StringEncoding]));
    
    return self;
}

- (void)helloWorld
{
    printf("Hello world");
}

- (void)setText:(NSString *)text
{
    self.cppItem->setText(std::string([text cStringUsingEncoding:NSUTF8StringEncoding]));
}

- (NSString *)getText
{
    return [NSString stringWithUTF8String:self.cppItem->getText().c_str()];
}

- (void)setNumber:(int)number
{
    self.cppItem->setNumber(number);
}

- (int)getNumber
{
    return self.cppItem->getNumber();
}
@end

 

 

4. 브릿지 헤더에 만든 Objective C++의 헤더 추가하기

아래와 같이 방금 만든 Objective C++의 헤더를 추가해주세요. 이제 준비는 끝났습니다.

[project name]-Bridging-Header.h

// CppTest-Bridging-Header.h

#import "CWrapper.h"

 

5. Swift에서 호출하기

 

ViewController.swift

//  ViewController.swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let cppItem = CWrapper();

        cppItem.helloWorld()
        print(cppItem.getText())
        cppItem.setText("This is test string")
        print(cppItem.getText())

        
        let cppItem2 = CWrapper(text: "Hi my name is cpp");
        print(cppItem2?.getText())
        
        cppItem2?.setNumber(33)
        print(cppItem2?.getNumber())
    }
}

 

실행하면 콘솔에 다음과 같은 로그를 볼 수 있습니다.

(std::endl은 콘솔에서는 동작하지 않네요ㅠ ㅎㅎ)

 

[참조]

(첫 번째 사진)

https://medium.com/@cecilia.humlelu/using-c-c-and-objective-c-frameworks-in-swift-apps-6a60e5f71c36

 

Using C, C++ and Objective-C frameworks in Swift apps

I did a talk in try!Swift Tokyo this year about using C, C++ and Objective-C frameworks in Swift apps. The presentation was quite concise…

medium.com

https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c

 

Importing Swift into Objective-C | Apple Developer Documentation

Article Importing Swift into Objective-C Access Swift types and declarations from within your Objective-C codebase. OverviewYou can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header fi

developer.apple.com

https://www.ekreative.com/blog/using-c-code-and-libraries-in-applications-written-in-swift/

 

Using C ++ code and libraries in applications written in Swift

Swift is a cool high-level programming language, but it’s still quite young and doesn’t have as many libraries and components as Objective-C.

www.ekreative.com

 

반응형