OC與Swift混編(基于Swift 4.1)
1古徒、在OC項(xiàng)目中,新建一個(gè)swift文件后會(huì)提示要不要自動(dòng)新建Bridging_Header
柱搜,由于項(xiàng)目中存在多個(gè)target块茁,自動(dòng)新建會(huì)新建多個(gè),所以不是很推薦這種方式辫狼,自己新建也很方便初斑,新建header file
后,在Build Settings -> Swift Compiler - general -> Objective-C Bridging Header
中寫入即可膨处,然后在Objective-C Bridging Header
的下方有一欄Objective-C Generated Interface Header Name
是系統(tǒng)生成的文件见秤,固定格式為項(xiàng)目名-Swift.h
。
-
Bridging_Header
文件可以理解為swift版本的PCH文件真椿,但只能給swift文件使用鹃答,由于swift文件無(wú)法直接import
OC文件,混編時(shí)突硝,需要在Bridging_Header
中import好OC類测摔; -
項(xiàng)目名-Swift.h
這個(gè)文件是OC調(diào)用swift類需要用到的,同理上一條解恰,OC中也是無(wú)法直接import
swift的锋八,但是可以import
這個(gè)文件,并且項(xiàng)目名-Swift.h
也是不需要我們自己維護(hù)护盈,只要OC中import
了該文件挟纱,就可以直接使用了,所以我是把項(xiàng)目名-Swift.h
放在了OC的PCH中黄琼。
2樊销、(重要
)網(wǎng)上混編的文章都是通過demo來(lái)演示的整慎,并沒有實(shí)際項(xiàng)目中復(fù)雜且各種父類宏的使用,所以在說(shuō)完第一點(diǎn)之后就直接開始編寫了围苫,并沒有提到可能會(huì)遇到的坑裤园,我雖然只修改了一個(gè)VC,但總結(jié)下來(lái)的話也有下面幾點(diǎn):
- 在
Bridging_Header
中import
是沒有提示的<粮E±俊! - 在
Bridging_Header
中import
是不會(huì)加載被import
文件中的其他類腺占,如果用到需要另外再import
淤袜; - 在
Bridging_Header
中被import
的OC文件一定要確保用到的類被正確import
,否則會(huì)報(bào)文件未找到衰伯; - 由于Swift無(wú)法公用OC的宏定義铡羡,所以還要確保在
Bridging_Header
中被import
的.h文件沒有用到OC的宏定義,例如通用的block回調(diào)之類意鲸。
在寫代碼過程中烦周,可能會(huì)遇到系統(tǒng)提示fix給參數(shù)添加了? ! ??
之類的字符。
可選值
打包wrap
(?
)
怎顾?
表示有值或者為空读慎。Eg: var name : String?
表示name可能有值也可能為空,可以理解為可選值類型是一個(gè)盒子槐雾,這個(gè)盒子有有值和無(wú)值兩種情況夭委,也就是可選值變量對(duì)有值或無(wú)值進(jìn)行了打包操作。
var a :Int?
var b :Int
雖然都是Int類型募强,但實(shí)際上a和b是不一樣的株灸,a屬于可選Int類型,b屬于Int類型
钻注。
- eg:
var aaa: Int? = 30
print(aaa)
會(huì)報(bào)一個(gè)Expression implicitly coerced from 'Int?' to Any
的警告蚂且,意思是把可選值類型隱式地強(qiáng)制轉(zhuǎn)換成任意類型來(lái)處理,可修改為print(aaa as Any)
消除警告幅恋。
但這并不好杏死,因?yàn)檫€有隱患
print(aaa + 1)
這樣更能直白的表示出可選值和非可選值的區(qū)別,會(huì)直接報(bào)錯(cuò):Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
捆交,提示沒有對(duì)Int?進(jìn)行解包unwrapped
淑翼,且直接對(duì)可選類型做了加一操作,Swift是強(qiáng)類型語(yǔ)言品追,在編譯階段就為我們排除了很大一部分的類型不匹配的錯(cuò)誤玄括,例如OC中int和float類型相加并不會(huì)報(bào)錯(cuò)隱式類型轉(zhuǎn)換
,而在Swift中則不行肉瓦,所以這里相當(dāng)于是將可選值的盒子進(jìn)行了加一的操作遭京,而不是對(duì)可選值盒子中的內(nèi)容進(jìn)行加一,就報(bào)錯(cuò)了哪雕。
解包Unwarpping optionals
既然有打包船殉,那么肯定就有解包斯嚎,就是把值從盒子內(nèi)取出來(lái)
- 1、強(qiáng)制解包
Force unwrapping
(!
)
針對(duì)上面的例子
print(aaa! + 1)
這樣就解包了堡僻,變量名后的感嘆號(hào)告訴編譯器糠惫,我想看下盒子里面的內(nèi)容并取出來(lái)里面的值
钉疫,但是,使用強(qiáng)制解包應(yīng)該謹(jǐn)慎的使用陌选。
還是針對(duì)上面的例子蹄溉,由于aaa
被定義為可選值變量咨油,在使用過程中可能會(huì)置換為nil
var aaa: Int? = 30
aaa = nil
print(aaa! + 1)
這樣就會(huì)報(bào)錯(cuò)Fatal error: Unexpectedly found nil while unwrapping an Optional value
柒爵,錯(cuò)誤原因是對(duì)一個(gè)值為空的變量進(jìn)行了解包,當(dāng)然可以在每次解包的時(shí)候判斷是否為nil
棉胀,但這無(wú)疑是增加了自己的代碼及工作量法瑟,并且如果萬(wàn)一忘記了的話唁奢,程序還是會(huì)崩潰霎挟。
所以對(duì)于強(qiáng)制解包,推薦是只有在確定不為空的情況下才使用的
- 可選值綁定
Optional binding
(iflet
)
var aaa: Int? = 30
aaa = nil
if let bbb = aaa {
print(bbb + 1)
} else {
print("no")
}
上面的代碼使用了iflet
表達(dá)式來(lái)進(jìn)行了綁定麻掸,如果可選值內(nèi)容不為空酥夭,那么就會(huì)被解包,并且let
的常量名可定義為相同的脊奋,如:
var aaa: Int? = 30
aaa = nil
if let aaa = aaa {
print(aaa + 1)
} else {
print("no")
}
- 空值合并
Nil coalescing
(??
)
var aaa: Int? = 30
aaa = nil
var bbb = aaa ?? 20
print(bbb + 1)
這也是一種解包熬北,叫做空合運(yùn)算符,類似于三目運(yùn)算符诚隙,上面??
的意思表示如果aaa不為nil
讶隐,那么就將aaa的值給bbb,否則將bbb賦值為20久又。