Swift 連結 Swift、Objective-C、C++

本篇在說明 Swift 連結其他專案的 Swift、Objective-C、C++ 的方法與注意事項。

 

Swift 連結其他 Swift

 

假設有一個目錄 testClass,底下有三個程式 

 

main.swift

person.swift

year.swift

 

其中 person.swift 會使用 year.swift 的內容,現在新的專案需要用到 person.swift 與 year.swift。

 

要加入檔案或目錄時,要選擇 Xcode 功能表的

 

File -> Add Files to "myProject"...

 

此時有這些選擇,通常我都不選 Copy ites if needed,以免被引用的專案後來有更新時,引用的專案還是用已經複製進來的舊版資料。當然,這功能我也不清楚,也許未來真的有需要使用的機會。

 

image

 

失敗方法

 

首先先談會失敗的方法,就是選擇 testClass 目錄,然後選 Create folder references,這時會在主架構中看到所加入的目錄,是藍色檔案夾圖示,打開也可以看到文件,無法正確編譯。

 

image

 

目前所知原因大概是只有目錄被加入專案中,但目錄下的檔案沒有加入專案,所以無法使用。

 

成功方法(一)

 

同樣將 testClass 加入專案中,不過這次是選擇 Create groups,就會看到如下黃色檔案夾圖示,也有三個引用進來的檔案。

 

image

 

此時編譯依然會失敗,主要是因為有個 main.swift,大概是什麼重要的進入點,反正這個我們也不需要,只要把 main.swift 移除,記住是要選擇移除參考關聯就好,不要真的把檔案丟到圾垃桶去了。

 

image

 

移除 main.swift 的參考關聯後,就可以順利執行了。

 

成功方法(二)

 

在程式專案架構中按下滑鼠右鍵,選擇 New Group 或 New Group without Folder,前者是在檔案目錄中實際建立該目錄,後者則是虛擬的架構,沒有真實目錄。

 

個人以為,若沒有實際複製檔案進來,那就選後者就可以了,不然會有空目錄產生。

 

image

 

建立好目錄之後,可以取名為 testClass,這就是黃色的檔案夾圖示。

 

再把 person.swift 與 year.swift 二個檔案使用關聯的方式加入,放在該目錄中,看起來就像方法一的架構,同樣也可以正常執行了。

 

Swift 連結 Objective-C

 

重點是要產生一個 "專案名-Bridging-Header.h" 的檔案,裡面要 import Objective-C 程式的 .h 檔案,這樣就可以讓 Swift 程式與 Objective-C 的程式產生連結了,方法見下。

 

先準備了一個 Objective-C 測試程式,程式很簡單,就是一個 OCClass 的物件,傳入一個數字,可回該數字再加上 2000。

 

main.m

 

 

#import <Foundation/Foundation.h>

#import "OCClass.h"

 

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

    OCClass *oc = [[OCClass alloc] init];

    [oc setAge:50];

    int y = [oc getYear];

    NSLog(@"Year is %i",y);

    return 0;

}

 

OCClass.h

 

@interface OCClass : NSObject

{

  int age;

}

-(int) age;

-(void) setAge: (int) p;

-(int) getYear;

@end

 

OCClass.m

 

#import <Foundation/Foundation.h>

#import "OCClass.h"

 

@implementation OCClass

 

-(int) age

{

  return age;

}

 

-(void) setAge: (int) p

{

  age = p;

}

 

-(int) getYear

{

    return age + 2000;

}

 

@end

 

一開始設定將整個目錄用 Add Group 的方式加入專案中,但沒有 copy 進來,Xcode 有問要不要建立 testLink-Bridging-Header.h,同意之後,卻是在 Objective-C 專案的目錄建 testLink-Bridging-Header.h,而且用起來有問題。

 

後來重做一次,加入 OC 的檔案時,選擇將檔案 copy 進來,產生的 testLink-Bridging-Header.h 就是在自己的專案目錄中了。

 

此時在 testLink-Bridging-Header.h 中要加入一行

 

#import "OCClass.h"

 

這樣就表示和 OC 的程式連結了。不過在執行時,有一個問題產生:

 

image

 

大概是不認為 NSObject,後來在上面加入這一行就可以了。

 

#import <Foundation/Foundation.h>

 

後來又試出這行也可以加在 testLink-Bridging-Header.h,也就是該檔有這二行

 

#import <Foundation/Foundation.h>

#import "OCClass.h"

 

主程式如下

 

@IBAction func btRun(_ sender: Any) {

    let oc = OCClass()

    oc.setAge(50)

    let y = oc.getYear()

    lbLabel.stringValue = "The Year is \(y)"

}

 

執行結果成功:

image

要查 testLink-Bridging-Header.h 的設定要看這裡:

 

選專案 -> Targets -> Build Settings -> 

Swift Compiler - General -> Objective-C Bridging Header

 

看它的設定位置是不是正確。

 

image

 

Swift 連結 C++

 

Swift 無法直接連結 C++,查到的資料都說要利用 Objective-C 或 C 當成中間層來轉接。

 

利用 Objective-C++ 連結

 

工作原理和上面差不多,細節就不多說,先看檔案規劃。

 

底下 testCpp 就是某個 C++ 的專案,我們放在 Group 中,紅框的 CppClass.hpp 和 CppClass.cpp 就是原始檔。

 

綠框的 CppClass.h 和 CppClass.mm 是 Objective-C++,是後來產生的,也就是中間層,它呼叫 C++,並提供 Swift 呼叫的界面。

 

為了要識別 C++,所以要用 Objective-C++,副檔名是 .mm,不可以是 .m。

 

image

 

底下直接看程式了。

 

CppClass.hpp

 

#ifndef CppClass_hpp

#define CppClass_hpp

 

#include <stdio.h>

 

class CppClass

{

public:

    int age;

    CppClass(int i);

    int getYear();

};

 

#endif /* CppClass_hpp */

 

 

CppClass.cpp

 

#include "CppClass.hpp"

 

CppClass::CppClass(int i)

{

    age = i;

}

 

int CppClass::getYear()

{

    return age + 2000;

}

 

以上是 C++ 專案,傳入一個數字,可以傳回數字加 2000。

 

底下是新加入的 Objective-C++ 檔頭,宣告一個 OCClass 物件。

 

CppClass.h

 

#import <Foundation/Foundation.h>

 

@interface OCClass : NSObject

-(int) getYear;

@end

 

底下是 Objective-C++ 的程式,注意副檔名是 .mm

它負責連結 CppClass.hpp

 

OCClass 會呼叫 CppClass 物件,不過我不知道如何建立物件實體,只好使用如下用法。 

 

CppClass.mm

 

#import <Foundation/Foundation.h>

#import "CppClass.h"

#import "CppClass.hpp"

 

@implementation OCClass

 

-(int) getYear {

    int y = CppClass(50).getYear();

    return y;

}

 

@end

 

這是 testLink-Bridging-Header.h,它只有一行,負責連結 Objective-C

 

 

#import "CppClass.h"

 

 

主程式,它就是呼叫 OC 物件,而 OC 會去呼叫 C++。

 

@IBAction func btRun(_ sender: Any) {

    let oc = OCClass()

    let y = oc.getYear()

    lbLabel.stringValue = "The Year is \(y)"

}

 

程式結果相同。

image

這個測試比較可惜的是不知道如何建立 C++ 物件實體,要再研究才行。

 

利用 C 連結

 

暫時懶得測了.... ^_^!

 

Swift 連結 C

暫時懶得測了.... ^_^!

 
重要度:
文章分類:
電腦標籤:

發表新回應