swift與oc的互用--c語言API交互

轉自譯者:shockinglee(git主頁

作爲與Objective-C語言的互操作性的一部分,Swift也保持了一些與C語言的類型和功能的兼容性,如果你的代碼有需要,Swift還提供了使用常見的C結構和模式的方式,如果你的代碼需要的話。


基本數據類型

Swift提供了一些等同於C語言基本類型,如char、int、float和double等。然而,這些類型和Swift核心基本類型之間沒有隱式轉換,如Int。因此,只有你的代碼明確要求它們時再使用這些類型,而Int可以在任何你想使用它的時候使用。

 

枚舉

Swift引進了Swift枚舉標作爲任何用宏NS_ENUM來標記的C風格的枚舉。這意味着無論枚舉值是在系統框架還是在自定義的代碼中定義的,當他們導入到Swift時,他們的前綴名稱將被截斷。例如,看這個Objective-C枚舉:

  1. //Objective-C 
  2. typedef NS_ENUM(NSInteger, UITableViewCellStyle) { 
  3.     UITableViewCellStyleDefault, 
  4.     UITableViewCellStyleValue1, 
  5.     UITableViewCellStyleValue2, 
  6.     UITableViewCellStyleSubtitle 
  7. }; 

 

在Swift中這樣來使用:

  1. //Swift 
  2. enum UITableViewCellStyle: Int { 
  3.     case Default 
  4.     case Value1 
  5.     case Value2 
  6.     case Subtitle 

 

當您需要指向一個枚舉值時,使用以點(.)開頭的枚舉名稱:

  1. //Swift 
  2. let cellStyle: UITableViewCellStyle = .Default 

Swift也引進了標有NS_OPTIONS宏選項。而選項的行爲類似於引進的枚舉,選項還可以支持一些位操作,如&,|以及?。在Objective-C中,你用一個空的選項設置標示恆爲零(0)。在Swift中,使用nil代表沒有任何選項。

 

指針

只要可能,Swift儘可能避免讓您直接訪問指針。然而,當您需要直接操作內存的時候,Swift也爲您提供了多種指針類型。下面的表使用Type作爲佔位符類型名稱來表示語法的映射。

 對於參數,以下映射適用:

對於返回類型,變量和參數類型的多層次指針,以下映射應用:

對於類(class)類型,以下映射適用:

C 可變指針

當一個函數被聲明爲接受CMutablePointer<Type>參數時,這個函數可以接受下列任何一個類型作爲參數:


1.nil,作爲空指針傳入。

2.一個CMutablePointer<Type>值。

3.一個操作數是Type類型的左值的 in-out 表達式,作爲這個左值的內存地址傳入。

4.一個in-out Type[]值,作爲一個數組的起始指針傳入,並且它的生命週期將在這個調用期間被延長。

 

如果您像這樣聲明瞭一個函數:

  1. //Swift 
  2. func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ } 

 

那麼您可以使用以下任何一種方式來調用這個函數:

  1. //Swift 
  2. var x: Float = 0.0 
  3. var p: CMutablePointer<Float> = nil 
  4. var a: Float[] = [1.0, 2.0, 3.0] 
  5.  
  6. takesAMutablePointer(nil) 
  7. takesAMutablePointer(p) 
  8. takesAMutablePointer(&x) 
  9. takesAMutablePointer(&a) 

當函數被聲明使用一個CMutableVoidPointer參數,那麼這個函數接受任何和CMutablePointer<Type>類型相似的Type操作數。

 

如果您這樣定義了一個函數:

  1. //Swift 
  2. func takesAMutableVoidPointer(x: CMutableVoidPointer) { /* ... */ } 

 

那麼您可以使用以下任何一種方式來調用這個函數:  

  1. //Swift 
  2. var x: Float = 0.0, y: Int = 0 
  3. var p: CMutablePointer<Float> = nil, q: CMutablePointer<Int> = nil 
  4. var a: Float[] = [1.0, 2.0, 3.0], b: Int = [1, 2, 3] 
  5.  
  6. takesAMutableVoidPointer(nil) 
  7. takesAMutableVoidPointer(p) 
  8. takesAMutableVoidPointer(q) 
  9. takesAMutableVoidPointer(&x) 
  10. takesAMutableVoidPointer(&y) 
  11. takesAMutableVoidPointer(&a) 
  12. takesAMutableVoidPointer(&b) 

 

C 常指針

當一個函數被聲明爲接受CConstPointer<Type>參數時,這個函數可以接受下列任何一個類型作爲參數:

1.nil,作爲空指針傳入。

2.一個CMutablePointer<Type>, CMutableVoidPointer, CConstPointer<Type>, CConstVoidPointer, 或者在必要情況下轉換成CConstPointer<Type>的AutoreleasingUnsafePointer<Type>值。

3.一個操作數是Type類型的左值的in-out表達式,作爲這個左值的內存地址傳入。

4.一個Type[]數組值,作爲一個數組的起始指針傳入,並且它的生命週期將在這個調用期間被延長。

 

如果您這樣定義了一個函數:

  1. //Swift 
  2. func takesAConstPointer(x: CConstPointer<Float>) { /*...*/ } 

 

那麼您可以使用以下任何一種方式來調用這個函數:

  1. //Swift 
  2. var x: Float = 0.0 
  3. var p: CConstPointer<Float> = nil 
  4.  
  5. takesAConstPointer(nil) 
  6. takesAConstPointer(p) 
  7. takesAConstPointer(&x) 
  8. takesAConstPointer([1.0, 2.0, 3.0]) 

當函數被聲明使用一個CConstVoidPointer參數,那麼這個函數接受任何和CConstPointer<Type>相似類型的Type操作數。 ? 

 

如果您這樣定義了一個函數:

  1. //Swift 
  2. ????func takesAConstVoidPointer(x: CConstVoidPointer) { /* ... */ } 

 

那麼您可以使用以下任何一種方式來調用這個函數: ?

  1. //Swift 
  2. var x: Float = 0.0, y: Int = 0 
  3. var p: CConstPointer<Float> = nil, q: CConstPointer<Int> = nil takesAConstVoidPointer(nil) 
  4. takesAConstVoidPointer(p) 
  5. takesAConstVoidPointer(q) 
  6. takesAConstVoidPointer(&x) 
  7. takesAConstVoidPointer(&y) 
  8. takesAConstVoidPointer([1.0, 2.0, 3.0]) takesAConstVoidPointer([1, 2, 3]) 

 

自動釋放不安全指針

當一個函數被聲明接受AutoreleasingUnsafePointer<Type>參數時,這個函數可以接受下列任何一個類型作爲參數:

1.nil,作爲空指針傳入。

2.一個AutoreleasingUnsafePointer<Type>值。

3.其操作數是原始的,複製到一個臨時的沒有所有者的緩衝區的一個輸入輸出表達式,該緩衝區的地址傳遞給調用,並返回時,緩衝區中的值加載,保存,並重新分配到操作數。

 

注:這個列表沒有包含數組。

 

如果您這樣定義了一個函數:

  1. //Swift 
  2. func takesAnAutoreleasingPointer(x: AutoreleasingUnsafePointer<NSDate?>) { /* ... */ } 

 

那麼您可以使用以下任何一種方式來調用這個函數:

  1. //Swift 
  2. var x: NSDate? = nil 
  3. var p: AutoreleasingUnsafePointer<NSDate?> = nil 
  4. takesAnAutoreleasingPointer(nil) 
  5. takesAnAutoreleasingPointer(p) 
  6. takesAnAutoreleasingPointer(&x) 

注:C語言函數指針沒有被Swift引進。

 

全局常量

在C和Objective-C語言源文件中定義的全局常量會自動地被Swift編譯引進並做爲Swift的全局常量。

 


預處理指令

Swift編譯器不包含預處理器。取而代之的是,它充分利用了編譯時屬性,生成配置和語言特性來完成相同的功能。因此,Swift沒有引進預處理指令。

 

簡單宏

在C和Objective-C,您通常使用的#define指令定義的一個基本常數,在Swift,您可以使用全局常量來代替。例如:一個全局定義#define FADE_ANIMATION_DURATION 0.35,在Swift可以使用let FADE_ANIMATION_DURATION = 0.35來更好的表述。由於簡單的用於定義常量的宏會被直接被映射成Swift全局量,Swift編譯器會自動引進在C或Objective-C源文件中定義的簡單宏。

 

複雜宏

在C和Objective-C中使用的複雜宏在Swift中並沒有副本。複雜宏是那些不用來定義常量的宏,包含帶括號的函數式宏。您在C和Objective-C使用複雜的宏以避免類型檢查的限制,或避免重新鍵入大量的樣板代碼。然而,宏也會產生Bug和重構的困難。在Swift中你可以使用函數和泛型來達到同樣的效果,無需任何的妥協。因此,在C和Objective-C源文件中定義的複雜宏在Swift是不能使用的。

 

編譯配置

Swift代碼和C、Objective-C代碼被有條件地,以不同方式編輯。SWIFT代碼可以根據生成配置的評價可以有條件地編譯。生成配置包括true和false字面值、命令行標誌以及下表中的平臺測試函數。您可以使用-D <#Flag#>指定命令行標誌。

注意:arch(arm) 的編譯配置不會爲64位arm設備返回true。當爲32位iOS 模擬器編譯代碼時,arch(i386)的編譯配置返回true。

 

一個簡單的有條件編譯可以像下面這段代碼:

  1. #if build configuration 
  2.   statements 
  3. #else 
  4.   statements 
  5. #endif 

 

一個由零個或多個有效的Swift語句聲明的statements,可以包括表達式,語句和控制流語句。您可以添加額外的構建配置要求,條件編譯說明用&&和| |操作符,否定生成配置使用!操作符,添加條件控制塊用#elseif:

  1. #if build configuration && !build configuration 
  2.   statements 
  3. #elseif build configuration 
  4.   statements 
  5. #else 
  6.   statements 
  7. #endif 

與C語言編譯器的條件編譯相反,Swift條件編譯語句必須完全是自包含和語法有效的代碼塊。這是因爲即使它沒有被編譯的Swift代碼也是被進行語法檢查。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章