swift 與 OC 混編

前言:

Swift語言出來后,可能新的項目直接使用Swift來開發,但可能在過程中會遇到一些情況,某些已用OC寫好的類或封裝好的模塊,不想再在swift 中再寫一次,或者有一些第三方使用OC寫的,沒有swift版本,怎么辦?那就使用混編。這個在IOS8后是允許的.

先簡單的入手,先研究在同一個工程目錄下混合使用的情況.這里主要介紹swift類中調用OC方法和swift類中調用C函數以及OC類中調用swift的函數這三種類型的混編.另外,小編也是邊研究邊嘗試才做出結果的,因此命名并非規范命名,大家就不要糾結命名問題了.小編這里使用swift創建的工程,工程名為SwiftTest.(其實用OC創建工程也大同小異)

準備內容:

1.創建swift工程,工程名SwiftTest

2.創建一個swift的類

3.創建一個OC的類

4.創建兩個C語言的類(一個包含頭文件,另一個不包含頭文件)

創建結果如下圖:

接下來,先說一下,創建過程中的情況:

1.創建swift類,可以用快捷鍵 command+n

創建swift類的時候有兩種方式,如下圖

注意:選綠框中這兩個地方都可以創建swift類,語言選Swift,然后注意,一定要繼承于NSObject,這個非常重要,否則在OC中不做修改調不到這個類的方法,就比較麻煩了,還是一步到位,繼承NSObject吧.另外還要注意紅框的位置,創建時一定要手動選擇紅框中這一項(iOS的Source),別用默認的,默認的是(OS X 的Source),后邊會講為什么.

然后創建成功就是這樣的了

這個是選擇iOS 的 Source ,然后用Cocoa Touch Class 創建的,如果是用Swift File 創建的類,那上面圖片的綠框中就是 import ?Foundation 了,這個還好,影響不大(個人建議用Cocoa Touch Class,因為它導入的UIKit是包含Foundation的,當然還是看你的喜好了).但是如果你用的是默認的 OS X 的 Source,然后用Cocoa Class創建(Cocoa Touch Class他倆圖標是一樣的,不看名字還真沒看出來他倆有區別),那上面綠框中就是import cocoa,并且混編的時候會報錯.我上兩個圖(左邊默認,右邊選擇后的),大家就明白為什么會范這種錯誤了

2.創建OC類

這個不說怎么創建了,都會吧!但有一點得說,那就是,在swift工程中,不再使用頭文件和.m文件的方式了。所以也不需要使用import ""來導入頭文件。那swift 如何能訪問到OC的類聲明呢?其實,swift也是需要使用頭文件進行訪問的,只不過不再需要使用顯式的方式使用import進行導入。有兩種方式來實現這個頭文件的生成。

方式一:在一個全新的Swift,利用第一次新建提示的方式自動添加橋接頭文件。

這個是在swift項目中,創建其他語言類的時候(OC,C等),系統會提示你添加一個橋接頭文件,如圖

然后點擊藍色那個按鈕,就會生成一個橋接頭文件,這個文件的格式為"你的工程名字-Bridging-Header.h",如圖中綠框所示

有的可能是xcode配置問題,沒有提示,那也可以自己創建一個,格式得按照以上的格式,但還有一種方式,不僅能創建還可以改變這個格式,取一個自己喜歡的文件名,但需要修改一些配置.

方式二:新建一個頭文件,名為:JeckHeader.h

在targets->build settings ->Object-C Bridging Header 位置設為Swift/JeckHeader.h,如下圖所示,這個頭文件也就是橋接頭文件,代碼一會兒再說.

3.創建C語言類

這里有一個需要注意的地方,創建C語言的類,和創建OC類差不多,如圖選擇C File 創建就好了

但是,點擊Next會出現下圖界面,看到那個藍色的"√"沒有,加上√,創建的C語言的類,類似OC,會有一組兩個文件,一個是.c文件一個是.h文件,.h文件就是這個C語言的頭文件,如果取消√,創建的C語言的類是沒有頭文件的.為方便學習,我把含頭文件的和不含頭文件的類,都分別創建了,后邊代碼中會分別介紹他們怎么用.

到這里,我們的準備工作做完了,接下來,結合代碼,來研究一下,swift調用OC里的方法,swift調用C語言的函數,OC調用swift函數,OC調用C語言的函數這幾種情況,如果前邊的準備工作做好了,那接下來會很容易理解.

然后結合代碼講解比較直觀:

[objc]view plaincopy

//??SwiftClass.swift?類中的代碼,這里邊只是添加了一個函數,OC的類會調用這個方法

import?UIKit

classSwiftClass:?NSObject?{

func?sayHello(name:String)?->?String?{

let?greeting?="Hello"+?name?+"!"

returngreeting

}

}

[objc]view plaincopy

//??OCClass.m??OC的.m文件,這里實現了兩個方法并定義了一個C語言的函數,為了方便對比,方法里實現了block,在這個類中演示:OC調用swift類中的方法

#import?"OCClass.h"

#import?"SwiftTest-swift.h"http://細心的朋友一定注意到了,項目文件中并沒有這個頭文件,但實際上項目中是有的,你也可以用command+鼠標左鍵跳進去查看,是隱藏的,如果你是按照我前邊的講的創建的swift文件,那你在這里是可以導入這個頭文件的,格式為"工程名-swift.h",它就是項目中所有的swift類的頭文件.

@implementationOCClass

-(void)desc22{

//聲明block

int(^p)(int,int);

//把函數賦值給block

p?=?^(inta,intb){

returna?+?b;

};

//使用

intresult?=?p(10,40);

NSLog(@"swift調用OC方法輸出result:%d\n",result);

//OC中調用swift函數

SwiftClass*sc?=?[[SwiftClassalloc]init];//創建swift對象

NSString*str?=[scsayHello:@"jeck"];//用swift的對象調用自己的函數(方法)

NSLog(@"OC中調用swift函數輸出?%@",str);

}

//定義函數

intsum2(inta,intb){

returna?+?b;

}

-(void)desc2{

//2.聲明block

int(^p)(int,int);

//3.把函數賦值給block

//p?=?sum2;

p?=?^(inta,intb){

returna?+?b;

};

//4.使用

intresult?=?p(10,40);

printf("swift調用OC方法輸出result:%d\n",result);

}

[objc]view plaincopy

//??OCClass.h?OC的頭文件,聲明了.m中的兩個方法和一個C語言函數,為了能被外界調用到

#import?

@interfaceOCClass?:?NSObject

intsum2(inta,intb);

-(void)desc22;

-(void)desc2;

@end

[objc]view plaincopy

//??CClass.c??C語言類的.c文件,定義了兩個函數

#include?"CClass.h"

//1.定義函數

intsum3(inta,intb)

{

returna+b;

}

voiddesc3(){

//2.聲明函數指針

int(*p)(int,int);

//3.函數指針指向函數

p?=?sum3;

//4.使用

intresult?=?p(10,10);

printf("swift調用有頭文件的C函數輸出:%d\n",result);

}

[objc]view plaincopy

//??CClass.h??C語言類的頭文件,聲明了兩個函數,作用同OC,方便外界調用

#ifndef?CClass_h

#define?CClass_h

#include?

//和OC中類似,在C的頭文件中聲明兩個函數

intsum3(inta,intb);

voiddesc3();

#endif?/*?CClass_h?*/

[objc]view plaincopy

//??CClassNo.c??這個類是沒有頭文件的c語言的類,實現了兩個函數

#include?

//1.定義函數

intsum1(inta,intb)

{

returna+b;

}

voiddesc1(){

//2.聲明函數指針

int(*p)(int,int);

//3.函數指針指向函數

p?=?sum1;

//4.使用

intresult?=?p(10,20);

printf("swift調用C函數輸出result:%d\n",result);

}

[objc]view plaincopy

//橋接頭文件SwiftTest-Bridging-Header.h

//導入C類

#import?"CClass.h"

//導入OC類

#import?"OCClass.h"

//聲明沒有頭文件的C語言類中的函數

voiddesc1();

intsum1(inta,intb);

[objc]view plaincopy

//??ViewController.swift??這個是創建工程的時候,系統自帶的那個swift類,在這里演示:swift調用OC方法,swift調用C方法

import?UIKit

classViewController:?UIViewController?{

override?func?viewDidLoad()?{

super.viewDidLoad()

//swift調用oc方法

let?funOC?=?OCClass()

funOC.desc2()

funOC.desc22()

let?funOCClass2=?sum2(10,1)

print("swift調用OC類中的C函數輸出:\(funOCClass2)")

//swift調用c函數(無頭文件)

desc1()

let?funcCClassss?=?sum1(10,2)

print("swift調用沒有頭文件的C語言類輸出:\(funcCClassss)")//12

//swift調用c函數(有頭文件)

desc3()

let?funcCClass33=?sum3(10,3)

print("swift調用含有頭文件的C語言類輸出:\(funcCClass33)")

}

到這里,就已經匯編成功了,下面是運行的結果

swift調用OC方法輸出result:50

2016-05-26 15:31:00.791 SwiftTest[2962:140487] swift調用OC方法輸出result:50

2016-05-26 15:31:00.807 SwiftTest[2962:140487] OC調用swift函數輸出Hellojeck!

swift調用OC類中的C函數輸出:11

swift調用C函數輸出result:30

swift調用沒有頭文件的C語言類輸出:12

swift調用有頭文件的C函數輸出:20

swift調用含有頭文件的C語言類輸出:13

最后,還得要強調一下:

1.Swift調用OC的方法,關鍵是橋接頭文件,這個必須創建正確并且配置正確,然后把你想要調用的OC或者C的頭文件(沒有頭文件也要聲明函數)導入到橋接頭文件里,Swift才能正常調用OC和C;

2.在OC中要想使用某個類,必須有頭文件,而swift文件卻沒有頭文件,所在咱們想必也需要產生一個頭文件,但對于OC調用swift ?的頭文件比較特殊.因頭文件里面的機制是自動生成的,不建議手寫.(注意:系統設置的頭文件,在工程中是看不到的.)

3.其實,可以選中targets->build

settings ->packaging->Product Module Name, 在這里查看和設置模塊名,這個名稱很重要

swift 的頭文件就是根據這個來命名的。(我的圖片為啥上傳不了了,我借幾張圖說明一下吧)

雖然你看圖中有這個import "SwiftModule-swift.h"但你在整個工程中是找不到這個文件的,但可以使用CMD+ 鼠標點擊可看這個頭文件中的內容。

雖然你看圖中有這個import "SwiftModule-swift.h"但你在整個工程中是找不到這個文件的,但可以使用CMD+ 鼠標點擊可看這個頭文件中的內容。

注:

凡是用Swift寫的類,如果不繼成自NSObject或NSObject 的派生類,哪么編譯后將不會生成對應的轉換類。從而使得OC 中找不到相應的聲明。

如我的例子中 class Act 這樣不會被編譯到SwiftModule-swift.h中,但寫為 class Act : NSObject,就可以編譯出相應的聲明。另外可以使用@objc加以聲明,但這個還是一樣,類最好繼承NSObject下來。就像下面:

[objc]view plaincopy

import?Foundation

@objc(Act)

classAct

{

func?hasAct(tag:Int)?->?String

{

switch(tag)

{

case1:return"Movie"

case2:return"CCTV"

case3:return"Sport?TV"

default:return"Area?TV"

}

}

@objc(init)//原本以為加上這個alloc就可以找到,但不行的。。。

init()

{

println("act?constructor?is?called.")

}

deinit

{

println("act?destroyed?is?called.")

}

}

但是在使用時你就會發現

act = [[Act alloc]init]; //報錯,找不到alloc,因此建議大家還是繼承NSObject.

雖然你看圖中有這個import "SwiftModule-swift.h"但你在整個工程中是找不到這個文件的,但可以使用CMD+ 鼠標點擊可看這個頭文件中的內容。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容