前言:
Swift語言出來后,可能新的項目直接使用Swift來開發(fā)赊锚,但可能在過程中會遇到一些情況部宿,某些已用OC寫好的類或封裝好的模塊,不想再在swift 中再寫一次楞抡,或者有一些第三方使用OC寫的,沒有swift版本,怎么辦?那就使用混編。這個在IOS8后是允許的.
先簡單的入手析藕,先研究在同一個工程目錄下混合使用的情況.這里主要介紹swift類中調(diào)用OC方法和swift類中調(diào)用C函數(shù)以及OC類中調(diào)用swift的函數(shù)這三種類型的混編.另外,小編也是邊研究邊嘗試才做出結(jié)果的,因此命名并非規(guī)范命名,大家就不要糾結(jié)命名問題了.小編這里使用swift創(chuàng)建的工程,工程名為SwiftTest.(其實用OC創(chuàng)建工程也大同小異)
準(zhǔn)備內(nèi)容:
1.創(chuàng)建swift工程,工程名SwiftTest
2.創(chuàng)建一個swift的類
3.創(chuàng)建一個OC的類
4.創(chuàng)建兩個C語言的類(一個包含頭文件,另一個不包含頭文件)
創(chuàng)建結(jié)果如下圖:
接下來,先說一下,創(chuàng)建過程中的情況:
1.創(chuàng)建swift類,可以用快捷鍵 command+n
創(chuàng)建swift類的時候有兩種方式,如下圖
注意:選綠框中這兩個地方都可以創(chuàng)建swift類,語言選Swift,然后注意,一定要繼承于NSObject,這個非常重要,否則在OC中不做修改調(diào)不到這個類的方法,就比較麻煩了,還是一步到位,繼承NSObject吧.另外還要注意紅框的位置,創(chuàng)建時一定要手動選擇紅框中這一項(iOS的Source),別用默認(rèn)的,默認(rèn)的是(OS X 的Source),后邊會講為什么.
然后創(chuàng)建成功就是這樣的了
這個是選擇iOS 的 Source ,然后用Cocoa Touch Class 創(chuàng)建的,如果是用Swift File 創(chuàng)建的類,那上面圖片的綠框中就是 import ?Foundation 了,這個還好,影響不大(個人建議用Cocoa Touch Class,因為它導(dǎo)入的UIKit是包含F(xiàn)oundation的,當(dāng)然還是看你的喜好了).但是如果你用的是默認(rèn)的 OS X 的 Source,然后用Cocoa Class創(chuàng)建(Cocoa Touch Class他倆圖標(biāo)是一樣的,不看名字還真沒看出來他倆有區(qū)別),那上面綠框中就是import cocoa,并且混編的時候會報錯.我上兩個圖(左邊默認(rèn),右邊選擇后的),大家就明白為什么會范這種錯誤了
2.創(chuàng)建OC類
這個不說怎么創(chuàng)建了,都會吧!但有一點得說,那就是,在swift工程中,不再使用頭文件和.m文件的方式了召廷。所以也不需要使用import ""來導(dǎo)入頭文件。那swift 如何能訪問到OC的類聲明呢?其實,swift也是需要使用頭文件進行訪問的竞慢,只不過不再需要使用顯式的方式使用import進行導(dǎo)入先紫。有兩種方式來實現(xiàn)這個頭文件的生成。
方式一:在一個全新的Swift筹煮,利用第一次新建提示的方式自動添加橋接頭文件遮精。
這個是在swift項目中,創(chuàng)建其他語言類的時候(OC,C等),系統(tǒng)會提示你添加一個橋接頭文件,如圖
然后點擊藍色那個按鈕,就會生成一個橋接頭文件,這個文件的格式為"你的工程名字-Bridging-Header.h",如圖中綠框所示
有的可能是xcode配置問題,沒有提示,那也可以自己創(chuàng)建一個,格式得按照以上的格式,但還有一種方式,不僅能創(chuàng)建還可以改變這個格式,取一個自己喜歡的文件名,但需要修改一些配置.
方式二:新建一個頭文件,名為:JeckHeader.h
在targets->build settings ->Object-C Bridging Header 位置設(shè)為Swift/JeckHeader.h,如下圖所示,這個頭文件也就是橋接頭文件,代碼一會兒再說.
3.創(chuàng)建C語言類
這里有一個需要注意的地方,創(chuàng)建C語言的類,和創(chuàng)建OC類差不多,如圖選擇C File 創(chuàng)建就好了
但是,點擊Next會出現(xiàn)下圖界面,看到那個藍色的"√"沒有,加上√,創(chuàng)建的C語言的類,類似OC,會有一組兩個文件,一個是.c文件一個是.h文件,.h文件就是這個C語言的頭文件,如果取消√,創(chuàng)建的C語言的類是沒有頭文件的.為方便學(xué)習(xí),我把含頭文件的和不含頭文件的類,都分別創(chuàng)建了,后邊代碼中會分別介紹他們怎么用.
到這里,我們的準(zhǔn)備工作做完了,接下來,結(jié)合代碼,來研究一下,swift調(diào)用OC里的方法,swift調(diào)用C語言的函數(shù),OC調(diào)用swift函數(shù),OC調(diào)用C語言的函數(shù)這幾種情況,如果前邊的準(zhǔn)備工作做好了,那接下來會很容易理解.
然后結(jié)合代碼講解比較直觀:
[objc]view plaincopy
//??SwiftClass.swift?類中的代碼,這里邊只是添加了一個函數(shù),OC的類會調(diào)用這個方法
import?UIKit
classSwiftClass:?NSObject?{
func?sayHello(name:String)?->?String?{
let?greeting?="Hello"+?name?+"!"
returngreeting
}
}
[objc]view plaincopy
//??OCClass.m??OC的.m文件,這里實現(xiàn)了兩個方法并定義了一個C語言的函數(shù),為了方便對比,方法里實現(xiàn)了block,在這個類中演示:OC調(diào)用swift類中的方法
#import?"OCClass.h"
#import?"SwiftTest-swift.h"http://細心的朋友一定注意到了,項目文件中并沒有這個頭文件,但實際上項目中是有的,你也可以用command+鼠標(biāo)左鍵跳進去查看,是隱藏的,如果你是按照我前邊的講的創(chuàng)建的swift文件,那你在這里是可以導(dǎo)入這個頭文件的,格式為"工程名-swift.h",它就是項目中所有的swift類的頭文件.
@implementationOCClass
-(void)desc22{
//聲明block
int(^p)(int,int);
//把函數(shù)賦值給block
p?=?^(inta,intb){
returna?+?b;
};
//使用
intresult?=?p(10,40);
NSLog(@"swift調(diào)用OC方法輸出result:%d\n",result);
//OC中調(diào)用swift函數(shù)
SwiftClass*sc?=?[[SwiftClassalloc]init];//創(chuàng)建swift對象
NSString*str?=[scsayHello:@"jeck"];//用swift的對象調(diào)用自己的函數(shù)(方法)
NSLog(@"OC中調(diào)用swift函數(shù)輸出?%@",str);
}
//定義函數(shù)
intsum2(inta,intb){
returna?+?b;
}
-(void)desc2{
//2.聲明block
int(^p)(int,int);
//3.把函數(shù)賦值給block
//p?=?sum2;
p?=?^(inta,intb){
returna?+?b;
};
//4.使用
intresult?=?p(10,40);
printf("swift調(diào)用OC方法輸出result:%d\n",result);
}
[objc]view plaincopy
//??OCClass.h?OC的頭文件,聲明了.m中的兩個方法和一個C語言函數(shù),為了能被外界調(diào)用到
#import?
@interfaceOCClass?:?NSObject
intsum2(inta,intb);
-(void)desc22;
-(void)desc2;
@end
[objc]view plaincopy
//??CClass.c??C語言類的.c文件,定義了兩個函數(shù)
#include?"CClass.h"
//1.定義函數(shù)
intsum3(inta,intb)
{
returna+b;
}
voiddesc3(){
//2.聲明函數(shù)指針
int(*p)(int,int);
//3.函數(shù)指針指向函數(shù)
p?=?sum3;
//4.使用
intresult?=?p(10,10);
printf("swift調(diào)用有頭文件的C函數(shù)輸出:%d\n",result);
}
[objc]view plaincopy
//??CClass.h??C語言類的頭文件,聲明了兩個函數(shù),作用同OC,方便外界調(diào)用
#ifndef?CClass_h
#define?CClass_h
#include?
//和OC中類似,在C的頭文件中聲明兩個函數(shù)
intsum3(inta,intb);
voiddesc3();
#endif?/*?CClass_h?*/
[objc]view plaincopy
//??CClassNo.c??這個類是沒有頭文件的c語言的類,實現(xiàn)了兩個函數(shù)
#include?
//1.定義函數(shù)
intsum1(inta,intb)
{
returna+b;
}
voiddesc1(){
//2.聲明函數(shù)指針
int(*p)(int,int);
//3.函數(shù)指針指向函數(shù)
p?=?sum1;
//4.使用
intresult?=?p(10,20);
printf("swift調(diào)用C函數(shù)輸出result:%d\n",result);
}
[objc]view plaincopy
//橋接頭文件SwiftTest-Bridging-Header.h
//導(dǎo)入C類
#import?"CClass.h"
//導(dǎo)入OC類
#import?"OCClass.h"
//聲明沒有頭文件的C語言類中的函數(shù)
voiddesc1();
intsum1(inta,intb);
[objc]view plaincopy
//??ViewController.swift??這個是創(chuàng)建工程的時候,系統(tǒng)自帶的那個swift類,在這里演示:swift調(diào)用OC方法,swift調(diào)用C方法
import?UIKit
classViewController:?UIViewController?{
override?func?viewDidLoad()?{
super.viewDidLoad()
//swift調(diào)用oc方法
let?funOC?=?OCClass()
funOC.desc2()
funOC.desc22()
let?funOCClass2=?sum2(10,1)
print("swift調(diào)用OC類中的C函數(shù)輸出:\(funOCClass2)")
//swift調(diào)用c函數(shù)(無頭文件)
desc1()
let?funcCClassss?=?sum1(10,2)
print("swift調(diào)用沒有頭文件的C語言類輸出:\(funcCClassss)")//12
//swift調(diào)用c函數(shù)(有頭文件)
desc3()
let?funcCClass33=?sum3(10,3)
print("swift調(diào)用含有頭文件的C語言類輸出:\(funcCClass33)")
}
到這里,就已經(jīng)匯編成功了,下面是運行的結(jié)果
swift調(diào)用OC方法輸出result:50
2016-05-26 15:31:00.791 SwiftTest[2962:140487] swift調(diào)用OC方法輸出result:50
2016-05-26 15:31:00.807 SwiftTest[2962:140487] OC調(diào)用swift函數(shù)輸出Hellojeck!
swift調(diào)用OC類中的C函數(shù)輸出:11
swift調(diào)用C函數(shù)輸出result:30
swift調(diào)用沒有頭文件的C語言類輸出:12
swift調(diào)用有頭文件的C函數(shù)輸出:20
swift調(diào)用含有頭文件的C語言類輸出:13
最后,還得要強調(diào)一下:
1.Swift調(diào)用OC的方法,關(guān)鍵是橋接頭文件,這個必須創(chuàng)建正確并且配置正確,然后把你想要調(diào)用的OC或者C的頭文件(沒有頭文件也要聲明函數(shù))導(dǎo)入到橋接頭文件里,Swift才能正常調(diào)用OC和C;
2.在OC中要想使用某個類,必須有頭文件,而swift文件卻沒有頭文件,所在咱們想必也需要產(chǎn)生一個頭文件,但對于OC調(diào)用swift ?的頭文件比較特殊.因頭文件里面的機制是自動生成的,不建議手寫.(注意:系統(tǒng)設(shè)置的頭文件败潦,在工程中是看不到的.)
3.其實,可以選中targets->build
settings ->packaging->Product Module Name, 在這里查看和設(shè)置模塊名本冲,這個名稱很重要
swift 的頭文件就是根據(jù)這個來命名的。(我的圖片為啥上傳不了了,我借幾張圖說明一下吧)
雖然你看圖中有這個import "SwiftModule-swift.h"但你在整個工程中是找不到這個文件的劫扒,但可以使用CMD+ 鼠標(biāo)點擊可看這個頭文件中的內(nèi)容檬洞。
雖然你看圖中有這個import "SwiftModule-swift.h"但你在整個工程中是找不到這個文件的,但可以使用CMD+ 鼠標(biāo)點擊可看這個頭文件中的內(nèi)容沟饥。
注:
凡是用Swift寫的類添怔,如果不繼成自NSObject或NSObject 的派生類,哪么編譯后將不會生成對應(yīng)的轉(zhuǎn)換類贤旷。從而使得OC 中找不到相應(yīng)的聲明广料。
如我的例子中 class Act 這樣不會被編譯到SwiftModule-swift.h中,但寫為 class Act : NSObject幼驶,就可以編譯出相應(yīng)的聲明艾杏。另外可以使用@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.")
}
}
但是在使用時你就會發(fā)現(xiàn)
act = [[Act alloc]init]; //報錯夸政,找不到alloc元旬,因此建議大家還是繼承NSObject.
雖然你看圖中有這個import "SwiftModule-swift.h"但你在整個工程中是找不到這個文件的,但可以使用CMD+ 鼠標(biāo)點擊可看這個頭文件中的內(nèi)容守问。