Swift 與 C 語言混合編程

前言

  • 做爲一種可與 Objective-C 相互調用的語言,Swift 也具備一些與 C 語言的類型和特性,若是你的代碼有須要,Swift 也提供了和常見的 C 代碼結構混合編程的編程方式。

一、基本數據類型

  • Swift 提供了一些和 C 語言的基本類型如 char,int,float,double 等價的 Swift 基本數據類型。然而,這些 Swift 的核心基本類型之間並不能隱式的相互轉換,如 Int。所以,只有你的代碼明確要求它們時再使用這些類型,而 Int 能夠在任何你想使用它的時候使用。編程

    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 引進了用宏 NS_ENUM 來標記的任何 C 風格的枚舉類型。這意味着不管枚舉值是在系統框架仍是在自定義的代碼中定義的,當他們導入到 Swift 時,他們的前綴名稱將被截斷。swift

  • Swift 也引進了標有 NS_OPTIONS 宏選項。而選項的行爲相似於引進的枚舉,選項還能夠支持一些位操做,如 &,| 和 ~
  • 在 Objective-C 中,你用一個空的選項設置標示恆爲零 (0)。在 Swift 中,使用 nil 表明沒有任何選項。數組

  • 看這個 Objective-C 枚舉安全

    // Objective-C
    
    typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
    
        UITableViewCellStyleDefault,
        UITableViewCellStyleValue1,
        UITableViewCellStyleValue2,
        UITableViewCellStyleSubtitle
    };
  • 在 Swift 中這樣來實現框架

    // Swift 
    
    enum UITableViewCellStyle: Int {
    
        case Default
        case Value1
        case Value2
        case Subtitle
    }
  • 當你須要指向一個枚舉值時,使用以點 (.) 開頭的枚舉名稱ide

    // Swift
    
    let cellStyle: UITableViewCellStyle = .Default

三、指針

  • Swift 儘量避免讓你直接訪問指針。然而,當你須要直接操做內存的時候,Swift 也爲你提供了多種指針類型。下面的表使用 Type 做爲佔位符類型名稱來表示語法的映射。函數

  • 對於參數,使用如下映射:測試

    C 句法 Swift 句法
    const void * CConstVoidPointer
    void * CConstPointer<Type>
    const Type * CUnsignedChar
    Type * CMutablePointer<Type>
  • 對於返回類型,變量和參數類型的多層次指針,使用如下映射:ui

    C 句法 Swift 句法
    void * COpaquePointer
    Type * UnsafePointer<Type>
  • 對於類(class)類型,使用如下映射:命令行

    C 句法 Swift 句法
    Type * const * CConstPointer<Type>
    Type * __strong * CMutablePointer<Type>
    Type ** AutoreleasingUnsafePointer<Type>

3.1 C 可變指針

  • 當一個函數被聲明爲接受 CMutablePointer<Type> 參數時,這個函數能夠接受下列任何一個類型做爲參數。

    • nil,做爲空指針傳入
    • 一個 CMutablePointer<Type> 類型的值
    • 一個操做數是 Type 類型的左值的輸入輸出表達式,做爲這個左值的內存地址傳入
    • 一個輸入輸出 Type[] 值,做爲一個數組的起始指針傳入,而且它的生命週期將在這個調用期間被延長

    • 若是你像這樣聲明瞭一個函數

      // Swift
      
      func takesAMutablePointer(x: CMutablePointer<Float>) { /*...*/ }
    • 那麼你能夠使用如下任何一種方式來調用這個函數

      // 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)
  • 當函數被聲明使用一個 CMutableVoidPointer 參數,那麼這個函數接受任何和 CMutablePointer<Type> 類似類型的 Type 操做數。

    • 若是你這樣定義了一個函數

      // Swift
      
      func takesAMutableVoidPointer(x: CMutableVoidPointer) { /*...*/ }
    • 那麼你能夠使用如下任何一種方式來調用這個函數

      // Swift
      
      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)

3.2 C 常指針

  • 當一個函數被聲明爲接受 CConstPointer<Type> 參數時,這個函數能夠接受下列任何一個類型做爲參數。

    • nil,做爲空指針傳入
    • 一個 CMutablePointer<Type>,CMutableVoidPointer,CConstPointer<Type>,CConstVoidPointer,或者在必要狀況下轉換成 CConstPointer<Type>AutoreleasingUnsafePointer<Type>
    • 一個操做數是 Type 類型的左值的輸入輸出表達式,做爲這個左值的內存地址傳入
    • 一個 Type[] 數組值,做爲一個數組的起始指針傳入,而且它的生命週期將在這個調用期間被延長

    • 若是你這樣定義了一個函數

      // Swift
      
      func takesAConstPointer(x: CConstPointer<Float>) { /*...*/ }
    • 那麼你能夠使用如下任何一種方式來調用這個函數

      // Swift
      
      var x: Float = 0.0
      var p: CConstPointer<Float> = nil
      
      takesAConstPointer(nil)
      takesAConstPointer(p)
      takesAConstPointer(&x)
      takesAConstPointer([1.0, 2.0, 3.0])
  • 當函數被聲明使用一個 CConstVoidPointer 參數,那麼這個函數接受任何和 CConstPointer<Type> 類似類型的 Type 操做數。

    • 若是你這樣定義了一個函數

      // Swift
      
      func takesAConstVoidPointer(x: CConstVoidPointer) { /*...*/ }
    • 那麼你能夠使用如下任何一種方式來調用這個函數

      // 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])

3.3 自動釋放不安全指針

  • 當一個函數被聲明爲接受 AutoreleasingUnsafePointer<Type> 參數時,這個函數能夠接受下列任何一個類型做爲參數。

    • nil,做爲空指針傳入
    • 一個 AutoreleasingUnsafePointer<Type>
    • 其操做數是原始的,複製到一個臨時的沒有全部者的緩衝區的一個輸入輸出表達式,該緩衝區的地址傳遞給調用,並返回時,緩衝區中的值加載,保存,並從新分配到操做數。

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

    • 若是你這樣定義了一個函數

      // Swift
      
      func takesAnAutoreleasingPointer(x: AutoreleasingUnsafePointer<NSDate?>) { /*...*/ }
    • 那麼你能夠使用如下任何一種方式來調用這個函數:

      // Swift
      
      var x: NSDate? = nil
      var p: AutoreleasingUnsafePointer<NSDate?> = nil
      
      takesAnAutoreleasingPointer(nil)
      takesAnAutoreleasingPointer(p)
      takesAnAutoreleasingPointer(&x)
    • 注意:C 語言函數指針沒有被 Swift 引進。

四、全局常量

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

五、預處理指令

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

5.1 簡單宏

  • 在 C 和 Objective-C 中一般使用的 #define 指令定義的一個宏常數,在 Swift 中能夠使用全局常量來代替。因爲簡單的用於定義常量的宏會被直接被映射成 Swift 全局量,Swift 編譯器會自動引進在 C 或 Objective-C 源文件中定義的簡單宏。

  • 例如: 一個全局定義 #define FADE_ANIMATION_DURATION 0.35,在 Swift能夠使用 let FADE_ANIMATION_DURATION = 0.35 來更好的表述。

5.2 複雜宏

  • 在 C 和 Objective-C 中使用的複雜宏在 Swift 中並無與之對應的定義。複雜宏是那些不用來定義常量的宏,而是用來定義包含小括號 () 函數的宏。你在 C 和 Objective-C 使用複雜的宏是用來避免類型檢查的限制和相同代碼的重複勞動。然而,宏也會產生 Bug 和重構的困難。在 Swift 中你能夠直接使用函數和泛型來達到一樣的效果。所以,在 C 和 Objective-C 源文件中定義的複雜宏在 Swift 是不能使用的。

5.3 編譯配置

  • Swift 代碼和 Objective-C 代碼以不一樣的方式進行條件編譯。Swift 代碼能夠根據生成配置的評價配進行有條件的編譯。生成配置包括 truefalse 字面值,命令行標誌,和下表中的平臺測試函數。你能夠使用 -D <#Flag#> 指定命令行標誌。

    函數 有效參數
    os() OSX, iOS
    arch() x86_64, arm, arm64, i386
    • 注意:arch(arm) 的生成配置不會爲 64 位 arm 設備返回 true,當代碼運行在爲 32 位的 iOS 模擬器器時,arch(i386) 的生成配置返回 true
  • 一個簡單的條件編譯須要如下代碼格式。

    #if build configuration
        statements
    #else
        statements
    #endif
  • 一個由零個或多個有效的 Swift 語句聲明的 statements,能夠包括表達式,語句和控制流語句。你能夠添加額外的構建配置要求,條件編譯說明用 &&|| 操做符以及 ! 操做符,添加條件控制塊用 #elseif

    #if build configuration && !build configuration
        statements
    #elseif build configuration
        statements
    #else
        statements
    #endif
  • 與 C 語言編譯器的條件編譯相反,Swift 條件編譯語句必須徹底是自包含和語法有效的代碼塊。這是由於 Swift 代碼即便沒有被編譯,也要所有進行語法檢查。

相關文章
相關標籤/搜索