Swift和C語(yǔ)言混合編程教程
作為一種可與 Objective-C 相互調(diào)用的語(yǔ)言,Swift 也具有一些與 C 語(yǔ)言的類型和特性,如果你的代碼有需要,Swift 也提供了和常見(jiàn)的 C 代碼結(jié)構(gòu)混合編程的編程方式。
基本數(shù)據(jù)類型
Swift 提供了一些和 C 語(yǔ)言的基本類型如char,int,float,double等價(jià)的 Swift 基本數(shù)據(jù)類型。然而,這些 Swift 的核心基本類型之間并不能隱式的相互轉(zhuǎn)換,如 Int。因此,只有你的代碼明確要求它們時(shí)再使用這些類型,而 Int 可以在任何你想使用它的時(shí)候使用。
C 類型 | Swift 類型 |
---|---|
bool | CBool |
char, signed char | CChar |
unsigned char | CUnsignedChar |
short | CShort |
unsigned short | CUnsignedShort |
int | CInt |
unsigned int | CUnsignedInt |
long | CLong |
unsigned long | CUnsignedLong |
long long | CLongLong |
unsigned long long | CUnsignedLongLong |
wchar_t | CWideChar |
char16_t | CChar16 |
char32_t | CChar32 |
float | CFloat |
double | CDouble |
枚舉
Swift 引進(jìn)了用宏NS_ENUM來(lái)標(biāo)記的任何 C 風(fēng)格的枚舉類型。這意味著無(wú)論枚舉值是在系統(tǒng)框架還是在自定義的代碼中定義的,當(dāng)他們導(dǎo)入到 Swift 時(shí),他們的前綴名稱將被截?cái)?。例如,看這個(gè) Objective-C 枚舉:
//Objective-C
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
在 Swift 中這樣來(lái)實(shí)現(xiàn):
//Swift
enum UITableViewCellStyle: Int {
case Default
case Value1
case Value2
case Subtitle
}
當(dāng)您需要指向一個(gè)枚舉值時(shí),使用以點(diǎn)(.)開(kāi)頭的枚舉名稱:
//Swift
let cellStyle: UITableViewCellStyle = .Default
Swift 也引進(jìn)了標(biāo)有NS_OPTIONS宏選項(xiàng)。而選項(xiàng)的行為類似于引進(jìn)的枚舉,選項(xiàng)還可以支持一些位操作,如 &,| 和 ~。在 Objective-C 中,你用一個(gè)空的選項(xiàng)設(shè)置標(biāo)示恒為零(0)。在 Swift 中,使用 nil代表沒(méi)有任何選項(xiàng)。
指針
Swift 盡可能避免讓您直接訪問(wèn)指針。然而,當(dāng)您需要直接操作內(nèi)存的時(shí)候,Swift 也為您提供了多種指針類型。下面的表使用 Type 作為占位符類型名稱來(lái)表示語(yǔ)法的映射。
對(duì)于參數(shù),使用以下映射:
C 句法 | Swift 句法 |
---|---|
const void * | CConstVoidPointer |
void * | CMutableVoidPointer |
const Type * | CConstPointer<Type> |
Type * | CMutablePointer<Type> |
對(duì)于返回類型,變量和參數(shù)類型的多層次指針,使用以下映射:
C 句法 | Swift 句法 |
---|---|
void * | COpaquePointer |
Type * | UnsafePointer<Type> |
對(duì)于類(class)類型,使用以下映射:
C 句法 | Swift 句法 |
---|---|
Type * const * | CConstPointer<Type> |
Type * __strong * | CMutablePointer<Type> |
Type ** | AutoreleasingUnsafePointer<Type> |
C 可變指針
當(dāng)一個(gè)函數(shù)被聲明為接受CMutablePointer<Type>參數(shù)時(shí),這個(gè)函數(shù)可以接受下列任何一個(gè)類型作為參數(shù):
•nil,作為空指針傳入
•一個(gè)CMutablePointer<Type>類型的值
•一個(gè)操作數(shù)是 Type 類型的左值的輸入輸出表達(dá)式,作為這個(gè)左值的內(nèi)存地址傳入
•一個(gè)輸入輸出 Type[] 值,作為一個(gè)數(shù)組的起始指針傳入,并且它的生命周期將在這個(gè)調(diào)用期間被延長(zhǎng)
如果您像這樣聲明了一個(gè)函數(shù):
//Swift
func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ }
那么您可以使用以下任何一種方式來(lái)調(diào)用這個(gè)函數(shù):
//Swift
var x: Float = 0.0
var p: CMutablePointer<Float> = nil
var a: Float[] = [1.0, 2.0, 3.0]
takesAMutablePointer(nil)
takesAMutablePointer(p)
takesAMutablePointer(&x)
takesAMutablePointer(&a)
當(dāng)函數(shù)被聲明使用一個(gè)CMutableVoidPointer參數(shù),那么這個(gè)函數(shù)接受任何和CMutablePointer<Type>相似類型的Type操作數(shù)。
如果您這樣定義了一個(gè)函數(shù):
//Swift
func takesAMutableVoidPointer(x: CMutableVoidPointer) { /* ... */ }
那么您可以使用以下任何一種方式來(lái)調(diào)用這個(gè)函數(shù):
var x: Float = 0.0, y: Int = 0
var p: CMutablePointer<Float> = nil, q: CMutablePointer<Int> = nil
var a: Float[] = [1.0, 2.0, 3.0], b: Int = [1, 2, 3]
takesAMutableVoidPointer(nil)
takesAMutableVoidPointer(p)
takesAMutableVoidPointer(q)
takesAMutableVoidPointer(&x)
takesAMutableVoidPointer(&y)
takesAMutableVoidPointer(&a)
takesAMutableVoidPointer(&b)
C 常指針
當(dāng)一個(gè)函數(shù)被聲明為接受CConstPointer<Type>參數(shù)時(shí),這個(gè)函數(shù)可以接受下列任何一個(gè)類型作為參數(shù):
•nil,作為空指針傳入
•一個(gè)CMutablePointer<Type>, CMutableVoidPointer, CConstPointer<Type>, CConstVoidPointer, 或者在必要情況下轉(zhuǎn)換成CConstPointer<Type>的AutoreleasingUnsafePointer<Type>值
•一個(gè)操作數(shù)是 Type 類型的左值的輸入輸出表達(dá)式,作為這個(gè)左值的內(nèi)存地址傳入
•一個(gè)Type[]數(shù)組值,作為一個(gè)數(shù)組的起始指針傳入,并且它的生命周期將在這個(gè)調(diào)用期間被延長(zhǎng)
//Swift
func takesAConstPointer(x: CConstPointer<Float>) { /*...*/ }
那么您可以使用以下任何一種方式來(lái)調(diào)用這個(gè)函數(shù):
//Swift
var x: Float = 0.0
var p: CConstPointer<Float> = nil
takesAConstPointer(nil)
takesAConstPointer(p)
takesAConstPointer(&x)
takesAConstPointer([1.0, 2.0, 3.0])
當(dāng)函數(shù)被聲明使用一個(gè)CConstVoidPointer參數(shù),那么這個(gè)函數(shù)接受任何和CConstPointer<Type> 相似類型的Type操作數(shù)。  如果您這樣定義了一個(gè)函數(shù):
//Swift 
func takesAConstVoidPointer(x: CConstVoidPointer) { /* ... */ }
那么您可以使用以下任何一種方式來(lái)調(diào)用這個(gè)函數(shù):
//Swift
var x: Float = 0.0, y: Int = 0
var p: CConstPointer<Float> = nil, q: CConstPointer<Int> = nil
takesAConstVoidPointer(nil)
takesAConstVoidPointer(p)
takesAConstVoidPointer(q)
takesAConstVoidPointer(&x)
takesAConstVoidPointer(&y)
takesAConstVoidPointer([1.0, 2.0, 3.0])
takesAConstVoidPointer([1, 2, 3])
自動(dòng)釋放不安全指針
當(dāng)一個(gè)函數(shù)被聲明為接受AutoreleasingUnsafePointer<Type>參數(shù)時(shí),這個(gè)函數(shù)可以接受下列任何一個(gè)類型作為參數(shù):
•nil,作為空指針傳入
•一個(gè)AutoreleasingUnsafePointer<Type>值
•其操作數(shù)是原始的,復(fù)制到一個(gè)臨時(shí)的沒(méi)有所有者的緩沖區(qū)的一個(gè)輸入輸出表達(dá)式,該緩沖區(qū)的地址傳遞給調(diào)用,并返回時(shí),緩沖區(qū)中的值加載,保存,并重新分配到操作數(shù)。
注意:這個(gè)列表沒(méi)有包含數(shù)組。
如果您這樣定義了一個(gè)函數(shù):
//Swift
func takesAnAutoreleasingPointer(x: AutoreleasingUnsafePointer<NSDate?>) { /* ... */ }
那么您可以使用以下任何一種方式來(lái)調(diào)用這個(gè)函數(shù):
//Swift
var x: NSDate? = nil
var p: AutoreleasingUnsafePointer<NSDate?> = nil

takesAnAutoreleasingPointer(nil)
takesAnAutoreleasingPointer(p)
takesAnAutoreleasingPointer(&x)
注意:C 語(yǔ)言函數(shù)指針沒(méi)有被 Swift 引進(jìn)。
全局常量
在 C 和 Objective-C 語(yǔ)言源文件中定義的全局常量會(huì)自動(dòng)地被 Swift 編譯引進(jìn)并做為 Swift 的全局常量。
預(yù)處理指令
Swift 編譯器不包含預(yù)處理器。取而代之的是,它充分利用了編譯時(shí)屬性,生成配置,和語(yǔ)言特性來(lái)完成相同的功能。因此,Swift 沒(méi)有引進(jìn)預(yù)處理指令。
簡(jiǎn)單宏
在 C 和 Objective-C,您通常使用的#define指令定義的一個(gè)宏常數(shù),在 Swift,您可以使用全局常量來(lái)代替。例如:一個(gè)全局定義#define FADE_ANIMATION_DURATION 0.35,在 Swift 可以使用let FADE_ANIMATION_DURATION = 0.35來(lái)更好的表述。由于簡(jiǎn)單的用于定義常量的宏會(huì)被直接被映射成 Swift 全局量,Swift 編譯器會(huì)自動(dòng)引進(jìn)在 C 或 Objective-C 源文件中定義的簡(jiǎn)單宏。
復(fù)雜宏
在 C 和 Objective-C 中使用的復(fù)雜宏在 Swift 中并沒(méi)有與之對(duì)應(yīng)的定義。復(fù)雜宏是那些不用來(lái)定義常量的宏,而是用來(lái)定義包含小括號(hào)(),函數(shù)的宏。您在 C 和 Objective-C 使用復(fù)雜的宏是用來(lái)避免類型檢查的限制和相同代碼的重復(fù)勞動(dòng)。然而,宏也會(huì)產(chǎn)生Bug和重構(gòu)的困難。在 Swift 中你可以直接使用函數(shù)和泛型來(lái)達(dá)到同樣的效果。因此,在 C 和 Objective-C 源文件中定義的復(fù)雜宏在 Swift 是不能使用的。
編譯配置
Swift 代碼和 Objective-C 代碼以不同的方式進(jìn)行條件編譯。Swift 代碼可以根據(jù)生成配置的評(píng)價(jià)配進(jìn)行有條件的編譯。生成配置包括 true 和 false 字面值,命令行標(biāo)志,和下表中的平臺(tái)測(cè)試函數(shù)。您可以使用-D <#Flag#>指定命令行標(biāo)志。
函數(shù) | 有效參數(shù) |
---|---|
os() | OSX, iOS |
arch() | x86_64, arm, arm64, i386 |
注意:arch(arm) 的生成配置不會(huì)為64位 arm 設(shè)備返回true,當(dāng)代碼運(yùn)行在為32位的 ios 模擬器器時(shí),arch(i386) 的生成配置返回true。
一個(gè)簡(jiǎn)單的條件編譯需要以下代碼格式:
#if build configuration
statements
#else
statements
#endif
一個(gè)由零個(gè)或多個(gè)有效的 Swift 語(yǔ)句聲明的statements,可以包括表達(dá)式,語(yǔ)句和控制流語(yǔ)句。您可以添加額外的構(gòu)建配置要求,條件編譯說(shuō)明用 && 和 | | 操作符以及 ! 操作符,添加條件控制塊用 #elseif:
#if build configuration && !build configuration
statements
#elseif build configuration
statements
#else
statements
#endif
與 C 語(yǔ)言編譯器的條件編譯相反,Swift 條件編譯語(yǔ)句必須完全是自包含和語(yǔ)法有效的代碼塊。這是因?yàn)?Swift 代碼即使沒(méi)有被編譯,也要全部進(jìn)行語(yǔ)法檢查。
相關(guān)文章
swift中自定義正則表達(dá)式運(yùn)算符=~詳解
這篇文章主要給大家介紹了關(guān)于swift中自定義正則表達(dá)式運(yùn)算符=~的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12Swift之UITabBarController 導(dǎo)航控制器的自定義
本文給大家介紹swift導(dǎo)航控制器之UITabBarController,本文通過(guò)代碼實(shí)例給大家講解swift導(dǎo)航控制器,導(dǎo)航控制器類繼承UITabBarController,代碼簡(jiǎn)單易懂,需要的朋友可以參考下2015-10-10Swift利用CoreData如何存儲(chǔ)多種數(shù)據(jù)類的通訊錄
這篇文章主要給大家介紹了關(guān)于Swift利用CoreData如何存儲(chǔ)多種數(shù)據(jù)類的通訊錄的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2017-12-12NotificationCenter類實(shí)現(xiàn)原理
這篇文章主要為大家介紹了NotificationCenter類實(shí)現(xiàn)原理源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03iOS中Swift指觸即開(kāi)集成Touch ID指紋識(shí)別功能的方法
隨著移動(dòng)支付時(shí)代的到來(lái),Touch ID 指紋驗(yàn)證迅速被支付寶,微信錢包普及,相信各位朋友使用后也大呼方便。下面給大家分享iOS中Swift指觸即開(kāi)集成Touch ID指紋識(shí)別功能的方法,一起看看吧2017-03-03