本篇在說明 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,以免被引用的專案後來有更新時,引用的專案還是用已經複製進來的舊版資料。當然,這功能我也不清楚,也許未來真的有需要使用的機會。
失敗方法
首先先談會失敗的方法,就是選擇 testClass 目錄,然後選 Create folder references,這時會在主架構中看到所加入的目錄,是藍色檔案夾圖示,打開也可以看到文件,無法正確編譯。
目前所知原因大概是只有目錄被加入專案中,但目錄下的檔案沒有加入專案,所以無法使用。
成功方法(一)
同樣將 testClass 加入專案中,不過這次是選擇 Create groups,就會看到如下黃色檔案夾圖示,也有三個引用進來的檔案。
此時編譯依然會失敗,主要是因為有個 main.swift,大概是什麼重要的進入點,反正這個我們也不需要,只要把 main.swift 移除,記住是要選擇移除參考關聯就好,不要真的把檔案丟到圾垃桶去了。
移除 main.swift 的參考關聯後,就可以順利執行了。
成功方法(二)
在程式專案架構中按下滑鼠右鍵,選擇 New Group 或 New Group without Folder,前者是在檔案目錄中實際建立該目錄,後者則是虛擬的架構,沒有真實目錄。
個人以為,若沒有實際複製檔案進來,那就選後者就可以了,不然會有空目錄產生。
建立好目錄之後,可以取名為 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 的程式連結了。不過在執行時,有一個問題產生:
大概是不認為 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)"
}
執行結果成功:
要查 testLink-Bridging-Header.h 的設定要看這裡:
選專案 -> Targets -> Build Settings ->
Swift Compiler - General -> Objective-C Bridging Header
看它的設定位置是不是正確。
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。
底下直接看程式了。
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)"
}
程式結果相同。
這個測試比較可惜的是不知道如何建立 C++ 物件實體,要再研究才行。
利用 C 連結
暫時懶得測了.... ^_^!
Swift 連結 C
暫時懶得測了.... ^_^!
- 瀏覽次數:9367
發表新回應