C の API との相互作用


Objective-C との相互運用性の一環として、Swift は、C 言語の型と機能との多くの互換性を維持しています。Swift はまた、コードがそれを必要とする場合には、一般的な C 言語構文やパターンでの作業の方法を提供します。


原始的な型


Swift は、C の原始的な整数と同じ型を提供します。たとえば、char、int、float、および double です。ただし、Int のように、これらの型と Swift の核となる整数型の間には暗黙の型変換はありません。したがって、コードでは、具体的にそれらを必要とする場合にはそれらの型を使用しますが、そうでなければ可能な限りは Int 型を使用して下さい。



C の型Swift の型
boolCBool
char, signed charCChar
unsigned charCUnsignedChar
shortCShort
unsigned shortCUnsignedShort
intCInt
unsigned intCUnsignedInt
longCLong
unsigned longCUnsignedLong
long longCLongLong
unsigned long longCUnsignedLongLong
wchar_tCWideChar
char16_tCChar16
char32_tCChar32
floatCFloat
doubleCDouble


グローバル定数


C と Objective-C のソースファイルで定義されたグローバル定数は自動的に Swift のグローバル定数として Swift のコンパイラによって import されます。


import された定数の列挙体と構造体


Objective-C では、プロパティとメソッドのパラメータに可能な値のリストを提供するために定数がよく使われます。Objective-C の typedef 宣言に、NS_TYPED_ENUM または NS_TYPED_EXTENSIBLE_ENUM マクロを使用して注釈を付け、その型の定数を Swift によって共通の型のメンバとして import できます。論理的に値を Swift の拡張機能で追加できない値のセットには、NS_TYPED_ENUM を使用します。拡張機能で展開できる値のセットには、NS_TYPED_EXTENSIBLE_ENUM を使用します。


可能な値の固定したセットを表す定数は、NS_TYPED_ENUM マクロを追加することによって構造体として import できます。たとえば、以下の TrafficLightColor 型の整数定数の Objective-C の宣言を考えてみましょう。


    <<OBJECTIVE-C>>

  1. // Store the three traffic light color options as 0, 1, and 2.
  2. typedef long TrafficLightColor NS_TYPED_ENUM;
  3. TrafficLightColor const TrafficLightColorRed;
  4. TrafficLightColor const TrafficLightColorYellow;
  5. TrafficLightColor const TrafficLightColorGreen;


Swift は、これを以下のように import します。


    << SWIFT >>

  1. struct TrafficLightColor: RawRepresentable, Equatable, Hashable {
  2.         typealias RawValue = Int
  3.         init(rawValue: RawValue)
  4.         var rawValue: RawValue { get }
  5.         static var red: TrafficLightColor { get }
  6.         static var yellow: TrafficLightColor { get }
  7.         static var green: TrafficLightColor { get }
  8. }


可能な値の拡張可能なセットを表す定数は、NS_TYPED_EXTENSIBLE_ENUM マクロを追加することによって構造体として import できます。たとえば以下の、交通信号でアクティブに点灯した色のセットを表す Objective-C 宣言を考えてみましょう。


    <<OBJECTIVE-C>>

  1. typedef TrafficLightColor TrafficLightCombo [3] NS_TYPED_EXTENSIBLE_ENUM;
  2. TrafficLightCombo const TrafficLightComboJustRed;
  3. TrafficLightCombo const TrafficLightComboJustYellow;
  4. TrafficLightCombo const TrafficLightComboJustGreen;
  5. // Some places use a combination of lights to indicate a specific condition.
  6. TrafficLightCombo const TrafficLightComboRedYellow;


Swift は、これを以下のように import します。


    << SWIFT >>

  1. struct TrafficLightCombo: RawRepresentable, Equatable, Hashable {
  2.         typealias RawValue = (TrafficLightColor, TrafficLightColor, TrafficLightColor)
  3.         init(_ rawValue: RawValue)
  4.         init(rawValue: RawValue)
  5.         var rawValue: RawValue { get }
  6.         static var justRed: TrafficLightCombo { get }
  7.         static var justYellow: TrafficLightCombo { get }
  8.         static var justGreen: TrafficLightCombo { get }
  9.         static var redYellow: TrafficLightCombo { get }
  10. }


この拡張可能な形式を使用する定数は、新しい値でセットを拡張するときに、引数ラベルを省略できる追加のイニシャライザとともに import されます。


NS_TYPED_EXTENSIBLE_ENUM マクロでマークされた型宣言から import された定数は、Swift コードで拡張して新しい値を追加できます。


    << SWIFT >>

  1. extension TrafficLightCombo {
  2.         static var all: TrafficLightCombo {
  3.                 return TrafficLightCombo((.red, .yellow, .green))
  4.         }
  5. }


注意: 文字列定数をグループ化するために使用された古い NS_STRING_ENUM マクロと NS_EXTENSIBLE_STRING_ENUM マクロを使用する Objective-C コードに遭遇することがあります。NS_TYPED_ENUMNS_TYPED_EXTENSIBLE_ENUM は、文字列定数を含む、あらゆる型の関連する定数をグループ化するときに使用します。


関数


Swift は、C のヘッダで宣言された全ての関数を Swift のグローバル関数として import します。たとえば、以下の C の関数の宣言を考えてみましょう。


    <<OBJECTIVE-C>>

  1. int product(int multiplier, int multiplicand);
  2. int quotient(int dividend, int devisor, int *remainder);
  3. struct Point2D createPoint2D(float x, float y);
  4. float distance(struct Point2D from, struct Point2D to);


Swift は、これを以下のように import します。


    << SWIFT >>

  1. func product(_ multiplier: Int32, _ multiplicand: Int32) -> Int32
  2. func quotient(_ dividend: Int32, _ devisor: Int32, _ remainder:
    UnsafeMutablePointer<Int32>) -> Int32
  3. func createPoint2D(_ x: Float, _ y: Float) -> Point2D
  4. func distance(_ from: Point2D, _ to: Point2D) -> Float


可変個引数の関数


Swift では、getVaList(_:) または withVaList(_:_:) 関数を使用して、vasprintf のような C の可変個引数の関数を呼び出すことができます。getVaList(_:) 関数は CVarArg 値の配列を取り、CVaListPointer 値を返しますが、ここで withVaList(_:_:) は、この値を直接返すのではなく、この値を本体内でクロージャーパラメータとして提供します。結果として得られる CVaListPointer 値は、C 可変個引数関数の va_list 引数に渡されます。


たとえば、Swift で vasprintf 関数を呼び出す方法は以下のとおりです。


    << SWIFT >>

  1. func swiftprintf(format: String, arguments: CVarArg...) -> String? {
  2.         return withVaList(arguments) { va_list in
  3.                 var buffer: UnsafeMutablePointer<Int8>? = nil
  4.                 return format.withCString { cString in
  5.                         guard vasprintf(&buffer, cString, va_list) != 0 else {
  6.                         return nil
  7.                         }
  8.                         return String(validatingUTF8: buffer!)
  9.                 }
  10.         }
  11. }
  12. print(swiftprintf(format: "√2 ≅ %g", arguments: sqrt(2.0))!)
  13. // Prints "√2 ≅ 1.41421"


注意: optional のポインタは、withVaList(_:invoke:) 関数に渡すことはできません。代わりに、Int.init(bitPattern:) イニシャライザを使用して、optional のポインタを Int として解釈し、これには、サポートされているすべてのプラットフォーム上のポインタと同じ C 可変個変数の呼び出し規約があります。


構造体


Swift は、C のヘッダで宣言された C の構造体を Swift の構造体として import します。import された Swift の構造体は、各 C の構造体フィールドの格納されたプロパティと、格納されたプロパティに対応するパラメータを持つイニシャライザを含んでいます。import されたメンバーのすべてがデフォルト値を持つ場合、Swift は引数を取らないデフォルトのイニシャライザも提供します。たとえば、以下の C 構造が与えられたとしましょう:


    <<OBJECTIVE-C>>

  1. struct Color {
  2.         float r, g, b;
  3. };
  4. typedef struct Color Color ;


対応する Swift 型はこうです:


    << SWIFT >>

  1. public struct Color {
  2.         var r: Float
  3.         var g: Float
  4.         var b: Float
  5.         init()
  6.         init(r: Float, g: Float, b: Float)
  7. }


型メンバとして関数を import


Core Foundation フレームワークのような C の API は、多くの場合、C 構造体を作成し、アクセスし、または変更する関数を提供します。独自のコードで CF_SWIFT_NAME マクロを使用すると、import された構造体型のメンバとして Swift は、C 関数を import できます。たとえば、以下の C 関数宣言が与えられたとします:


    <<OBJECTIVE-C>>

  1. Color ColorCreateWithCMYK(float c, float m, float y, float k)
    CF_SWIFT_NAME(Color.init(c:m:y:k:));
  2. float ColorGetHue(Color color) CF_SWIFT_NAME(getter:Color.hue(self:));
  3. void ColorSetHue(Color color, float hue)
    CF_SWIFT_NAME(setter:Color.hue(self:newValue:));
  4. Color ColorDarkenColor(Color color, float amount)
    CF_SWIFT_NAME(Color.darken(self:amount:));
  5. extern const Color ColorBondiBlue CF_SWIFT_NAME(Color.bondiBlue);
  6. Color ColorGetCalibrationColor(void) CF_SWIFT_NAME(getter:Color.calibration());
  7. Color ColorSetCalibrationColor(Color color)
    CF_SWIFT_NAME(setter:Color.calibration(newValue:));


Swift は、それらを型メンバとして import します。


    << SWIFT >>

  1. extension Color {
  2.         init(c: Float, m: Float, y: Float, k: Float)
  3.         var hue: Float { get set }
  4.         func darken(amount: Float) -> Color
  5.         static var bondiBlue: Color
  6.         static var calibration: Color
  7. }


CF_SWIFT_NAME マクロに渡される引数は、#selector 式と同じ構文を使用します。CF_SWIFT_NAME 引数での self の使用は、メソッド受信者を参照するインスタンスメソッドに使用されます。


注意: CF_SWIFT_NAME マクロを使用して import された型メンバの引数の数を変更したり、順序を変更することはできません。洗練された Swift インターフェイスから C 機能を提供するには、実装で必要な C 関数呼び出しを行う新しい Swift 関数を宣言してオーバーレイを作成します。


列挙型


NS_ENUM マクロでマークされた全ての C の列挙型を Swift は列挙型として Int の生の値型で Swift に import します。C の列挙型の case の名前への接頭辞は、Swift に import される時、システムフレームワークまたはカスタムコードで定義されているかにより削除されます。


たとえば、以下の C の列挙型は、NS_ENUM マクロを使用して宣言されています。


    <<OBJECTIVE-C>>

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


Swift では、以下のように import されます:


    << SWIFT >>

  1. enum UITableViewCellStyle: Int {
  2.        case `default`
  3.        case Value1
  4.        case Value2
  5.        case Subtitle
  6. }


列挙型の値を参照する場合、先頭のドット(.) を持つ値の名前を使用して下さい。


    << SWIFT >>

    let cellStyle: UITableViewCellStyle = .default



注意: Swift によって import された C の列挙型は、列挙型の case に対応しない生の値で初期化するときに失敗しません。これは、C との互換性のために行われ、これは、内部的に使用された値を含む列挙型に格納される全ての値を許可しますが、ヘッダには表示されません。


NS_ENUM または NS_OPTIONS マクロでマークされていない C の列挙型は Swift の構造体として import されます。C の列挙型の各メンバは、Swift 構造体のメンバそれ自体ではなく、構造体型のグローバルの読み込み専用の計算されたプロパティとして import されます。


たとえば、以下の C 列挙型は NS_ENUM マクロを使用しては宣言されていません。


    <<OBJECTIVE-C>>

  1. typedef enum {
  2.         MessageDispositionUnread = 0,
  3.         MessageDispositionRead = 1,
  4.         MessageDispositionDeleted = -1,
  5. } MessageDisposition;


Swift では、これは以下のように import されます:


    << SWIFT >>

  1. struct MessageDisposition: RawRepresentable, Equatable {}
  2. var MessageDispositionUnread: MessageDisposition { get }
  3. var MessageDispositionRead: MessageDisposition { get }
  4. var MessageDispositionDeleted: MessageDisposition { get }


Swift は import された C の列挙型の Equatable プロトコルへの準拠を自動的に合成します。



Option のセット


Swift はまた、Swift の Option のセットとして NS_OPTIONS マクロでマークされた C の列挙体を import します。Option のセットは、接頭辞を option の値の名前から切り捨てることによって、import された列挙型と同様に振る舞います。


たとえば、以下の Objective-C の options の宣言を考えてみましょう:


    <<OBJECTIVE-C>>

  1. typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
  2.         UIViewAutoresizingNone                               = 0,
  3.         UIViewAutoresizingFlexibleLeftMargin        = 1 << 0,
  4.         UIViewAutoresizingFlexibleWidth                = 1 << 1,
  5.         UIViewAutoresizingFlexibleRightMargin     = 1 << 2,
  6.         UIViewAutoresizingFlexibleTopMargin        = 1 << 3,
  7.         UIViewAutoresizingFlexibleHeight               = 1 << 4,
  8.         UIViewAutoresizingFlexibleBottomMargin  = 1 << 5
  9. };


Swift では、これは以下のように import されます。


    << SWIFT >>

  1. public struct UIViewAutoresizing : OptionSet {
  2.         public init(rawValue: UInt)
  3.         public static var flexibleLeftMargin: UIViewAutoresizing { get }
  4.         public static var flexibleWidth: UIViewAutoresizing { get }
  5.         public static var flexibleRightMargin: UIViewAutoresizing { get }
  6.         public static var flexibleTopMargin: UIViewAutoresizing { get }
  7.         public static var flexibleHeight: UIViewAutoresizing { get }
  8.         public static var flexibleBottomMargin: UIViewAutoresizing { get }
  9. }


Objective-C では、option セットは整数値のビットマスクです。ビット単位の OR 演算子(|) を使用して option 値を結合し、ビット単位の AND 演算子(&) を使用して option 値を確認して下さい。定数値または式から新しい option セットを作成し、空の option セットは定数ゼロ(0) で表されます。


Swift では、Option セットは OptionSet プロトコルに準拠した構造体で表され、各 option 値ごとに静的変数があります。配列リテラルを使用して新しい option セットの値を作成し、列挙型に似た先行ドット(.) で option 値にアクセスできます。空の配列リテラル([]) から、またはデフォルトのイニシャライザを呼び出すことによって、空の option セットを作成できます。


注意: NS_OPTIONS マクロでマークされた C の列挙型を import するとき、Swift は空の option セットを使用して options を指定しないため、0 の値を持つメンバを使用不可として Swift はマークします。


option セットは、Swift の Set コレクション型のように振る舞います。option 値を追加するには、insert(_:) または formUnion(_:) メソッドを使用し、option 値を削除するには、remove(_:) または subtract(_:) メソッドを使用し、また option 値を確認するには contains(_:) メソッドを使用して下さい。


    << SWIFT >>

  1. let options: Data.Base64EncodingOptions = [
  2.         .lineLength64Characters,
  3.         .endLineWithLineFeed
  4. ]
  5. let string = data.base64EncodedString(options: options)


ユニオン


Swift は Swift 構造体として C のユニオン (union) を import します。Swift は union をサポートしていませんが、Swift 構造体として import された C の union はまだ C の union のように動作します。たとえば、isAlive および isDead フィールドを持つ SchroedingersCat という名前の C のユニオンを考えます。


    <<OBJECTIVE-C>>

  1. union SchroedingersCat {
  2.         bool isAlive;
  3.         bool isDead;
  4. };


Swift では、これはこのように import されます。


    << SWIFT >>

  1. struct SchroedingersCat {
  2.         var isAlive: Bool { get set }
  3.         var isDead: Bool { get set }
  4.         init(isAlive: Bool)
  5.         init(isDead: Bool)
  6.         init()
  7. }


C のユニオンは、すべてのフィールドに同じ基本メモリー・アドレスを使用するため、Swift によって import されたユニオン内の計算されたプロパティーはすべて同じ基本メモリーを使用します。その結果、import された構造体のインスタンスの計算されたプロパティの値を変更すると、その構造体で定義された他のすべてのプロパティの値を変更します。


以下の例では、SchroedingersCat 構造体のインスタンス上の isAlive の計算されたプロパティの値を変更すると、インスタンスの isDead の計算されたプロパティの値も変更します。


    << SWIFT >>

  1. var mittens = SchroedingersCat(isAlive: false)
  2. print(mittens.isAlive, mittens.isDead)
  3. // Prints "false false"
  4. mittens.isAlive = true
  5. print(mittens.isDead)
  6. // Prints "true"


ビットフィールド


Swift は、Foundation の NSDecimal 型にあるような構造体のビットフィールドを、計算されたプロパティとして import します。ビットフィールドに対応する計算されたプロパティにアクセスすると、Swift は互換性のある Swift 型に、またそれから自動的に値を変換します。


名前のない構造体と union のフィールド


C の structunion 型は、名前がなく、名前のない型としてフィールドを定義できます。名前のないフィールドは名前が付いたフィールドで struct または union の入れ子になった型から成ります。


たとえば、名前のない union 型の中に入れ子になったたフィールドの layersheight と、名前のないの struct 型のフィールドの topping を含む Cake という C の構造体を考えてみましょう。


    <<OBJECTIVE-C>>

  1. struct Cake {
  2.         union {
  3.                 int layers;
  4.                 double height;
  5.         };
  6.         struct {
  7.                 bool icing;
  8.                 bool sprinkles;
  9.         } toppings;
  10. };


Cake 構造体を import した後、初期化して以下のように使用できます。


    << SWIFT >>

  1. var simpleCake = Cake()
  2. simpleCake.layers = 5
  3. print(simpleCake.toppings.icing)
  4. // Prints "false"


Cake 構造体は、以下のように、そのフィールドのカスタム値で構造体を初期化するために使用できるメンバ毎のイニシャライザで import されます。


    << SWIFT >>

  1. let cake = Cake(
  2.         .init(layers: 2),
  3.         toppings: .init(icing: true, sprinkles: false)
  4. )
  5. print("The cake has \(cake.layers) layers.")
  6. // Prints "The cake has 2 layers."
  7. print("Does it have sprinkles?", cake.toppings.sprinkles ? "Yes." : "No.")
  8. // Prints "Does it have sprinkles? No."


Cake 構造体の最初のフィールドは名前が付けられていないため、イニシャライザの最初のパラメータにはラベルがありません。Cake 構造体には名前のない型のフィールドがあるので、型推論を使用して選択された .init イニシャライザを使用して、構造体の名前のない各フィールドの初期値を設定します。


ポインタ


可能な限り、Swift はポインタへの直接のアクセスを与えることを回避します。しかし、メモリへの直接アクセスを必要とするために利用可能なさまざまなポインタ型があります。以下の表は、マッピングのための構文を示すために、プレースホルダの型の名前として Type を使用しています。


戻り値の型、変数、および引数については、以下のマッピングが適用されます。



C の構文Swift の構文
const Type *UnsafePointer<Type>
Type *UnsafeMutablePointer<Type>


クラス型の場合は、以下のマッピングが適用されます。



C の構文Swift の構文
Type * const *UnsafePointer<Type>
Type * __strong *UnsafeMutablePointer<Type>
Type **AutoreleasingUnsafeMutablePointer<Type>


型のない、生のメモリへのポインタについては、以下のマッピングが適用されます。



C の構文Swift の構文
const void *UnsafeRawPointer
void *UnsafeMutableRawPointer


Swift はまた、バッファを扱うためのポインタ型も提供します。これについては、バッファポインタ を参照してください。


不完全な struct 型のように、C ポインタが指す値の型を Swift で表現できない場合、ポインタは OpaquePointer として import されます。


定数ポインタ


関数が UnsafePointer<Type> 引数を取るように宣言されると、以下のいずれかを受け入れることができます。


関数に渡されたポインタは、関数呼び出しの間だけ有効であることが保証されています。関数が返した後でポインタを保持したりそれにアクセスしようとしないでください。


以下のような関数を宣言した場合:


    << SWIFT >>

  1. func takesAPointer(_ p: UnsafePointer<Float>) {
  2.         //...
  3. }


以下の方法のいずれでもそれを呼び出すことができます。


    << SWIFT >>

  1. var x: Float = 0.0
  2. takesAPointer(&x)
  3. takesAPointer([1.0, 2.0, 3.0])


関数が UnsafeRawPointer 引数を取るように宣言されると、任意の型の Type 用の UnsafePointer<Type> と同じオペランドをそれは受け入れる事ができます。


以下のような関数を宣言した場合:


    << SWIFT >>

  1. func takesARawPointer(_ p: UnsafeRawPointer?) {
  2.         // ...
  3. }


以下の方法のいずれでもそれを呼び出すことができます。


    << SWIFT >>

  1. var x: Float = 0.0, y: Int = 0
  2. takesARawPointer(&x)
  3. takesARawPointer(&y)
  4. takesARawPointer([1.0, 2.0, 3.0] as [Float])
  5. let intArray = [1, 2, 3]
  6. takesARawPointer(intArray)


可変ポインタ


関数が UnsafeMutablePointer<Type> 引数を取るように宣言されると、以下のいずれかをそれは受け入れる事ができます。


このような関数を宣言した場合:


    << SWIFT >>

  1. func takesAMutablePointer(_ p: UnsafeMutablePointer<Float>) {
  2.         //...
  3. }


以下の方法のいずれでもそれを呼び出すことができます。


    << SWIFT >>

  1. var x: Float = 0.0
  2. var a: [Float] = [1.0, 2.0, 3.0]
  3. takesAMutablePointer(&x)
  4. takesAMutablePointer(&a)


関数が UnsafeMutableRawPointer 引数を取るように宣言されると、任意の型の TypeUnsafeMutablePointer<Type> と同じオペランドを受け入れます。


以下のような関数を宣言した場合:


    << SWIFT >>

  1. func takesAMutableRawPointer(_ p: UnsafeMutableRawPointer?) {
  2.         // ...
  3. }


以下の方法のいずれでもそれを呼び出せます。


    << SWIFT >>

  1. var x: Float = 0.0, y: Int = 0
  2. var a: [Float] = [1.0, 2.0, 3.0], b: [Int] = [1, 2, 3]
  3. takesAMutableRawPointer(&x)
  4. takesAMutableRawPointer(&y)
  5. takesAMutableRawPointer(&a)
  6. takesAMutableRawPointer(&b)


自動解放ポインタ


関数が AutoreleasingUnsafeMutablePointer<Type> を取るように宣言されると、以下のいずれかを受け入れる事ができます。


このリストは、配列を含んでいないことに注意してください。


以下のような関数を宣言した場合:


    << SWIFT >>

  1. func takesAnAutoreleasingPointer(_ p: AutoreleasingUnsafeMutablePointer<NSDate?>) {
  2.         // ...
  3. }


以下の方法でそれを呼び出せます。


    << SWIFT >>

  1. var x: NSDate? = nil
  2. takesAnAutoreleasingPointer(&x)


ポインタの先の型は、ブリッジされません。たとえば、NSString ** は、 AutoreleasingUnsafeMutablePointer<NSString?> として Swift にやって来ますが、 AutoreleasingUnsafeMutablePointer<String?> としてではありません。


関数ポインタ


C の関数ポインタは @convention(c) 属性で示される、C の関数ポインタ呼び出し規約でクロージャとして Swift に import されます。たとえば、C 言語での int (*)(void) 型を持つ関数ポインタは @convention(c) () -> Int32 として Swift に import されます。


関数ポインタ引数をとる関数を呼び出すときは、最上位の Swift 関数、クロージャリテラル、または nil を渡すことができます。また、クロージャーの引数リストまたは本体で汎用型パラメーターが参照されていない限り、汎用型または汎用メソッドのクロージャプロパティを渡すこともできます。たとえば、Core Foundation の CFArrayCreateMutable(_:_:_:) 関数を考えてみましょう。CFArrayCreateMutable(_:_:_:) 関数は、CFArrayCallBacks 構造体を取り、この構造体は、関数ポインタのコールバックで初期化されます。


    << SWIFT >>

  1. func customCopyDescription(_ p: UnsafeRawPointer?) -> Unmanaged<CFString>? {
  2.         // return an Unmanaged<FString>? value
  3. }
  4. var callbacks = CFArrayCallBacks(
  5.         version: 0,
  6.         retain: nil,
  7.         release: nil,
  8.         copyDescription: customCopyDescription,
  9.         equal: { (p1, p2) -> DarwinBoolean in
  10.                 // return Bool value
  11.         }
  12. )
  13. var mutableArray = CFArrayCreateMutable(nil, 0, &callbacks)


上記の例では、CFArrayCallBacks イニシャライザは、retain および release パラメータに引数として nil 値を使用し、customCopyDescription パラメータの引数としての customCopyDescription(_:) 関数は、equal パラメータの引数としてクロージャリテラルを使用します。



注意: C 関数の参照呼び出し規則を持つ Swift 関数型だけが、関数ポインタ引数として使用できます。C の関数ポインタのように、@convention(c) 属性を持つ Swift の関数型は、その周囲の範囲の文脈をキャプチャーしません。

詳細については、Swift プログラミング言語(Swift 4.0.3)型の属性 を参照してください。


バッファポインタ


バッファポインタ は、メモリ領域への低レベルアクセスに使用されます。たとえば、バッファポインタを使用すると、効率的な処理と、アプリとサービスの間のデータのやりとりを行うことができます。


Swift には、以下のバッファポインタ型があります。


バッファポインタ型の、UnsafeBufferPointer および UnsafeMutableBufferPointer を使用すると、連続したメモリブロックを表示または変更できます。これらの型を使用すると、メモリをコレクションとしてアクセスでき、各アイテムは、バッファ型の Element 汎用型パラメータのインスタンスです。


生のバッファポインタ型、UnsafeRawBufferPointer および UnsafeMutableRawBufferPointer を使用すると、連続したメモリブロックを UInt8 値のコレクションとして表示または変更でき、各値はメモリの1バイトに対応します。これらの型を使用すると、コンパイラが確認した型の安全性を持たない生のメモリ上での操作や、同じメモリの複数の異なる型付きの解釈の間の切り替えなど、低レベルのプログラミングパターンを使用できます。


ヌルポインタ


Objective-C では、ポインタ型宣言は _Nullable_Nonnull 注釈を使用して、そのポインタが nil かまたは NULL 値を持つことができるかどうかを指定できます。Swift では、ヌルポインタは、optional のポインタ型の nil 値で表されます。メモリ内のアドレスの整数表現を取るポインタのイニシャライザは失敗可能です。optional でないポインタ型には nil 値を代入できません。


以下のマッピングが適用されます:


C の構文Swift の構文
const Type * _NonnullUnsafePointer<Type>
const Type * _NullableUnsafePointer<Type>?
const Type * _Null_unspecifiedUnsafePointer<Type>!


ポインタの計算


不透明なデータ型で作業する場合、安全でないポインター操作を実行する必要があります。Swift のポインタ値の計算演算子を使用して、指定されたオフセットで新しいポインタを作成することができます。


    << SWIFT >>

  1. let pointer: UnsafePointer<Int8>
  2. let offsetPointer = pointer + 24
  3. // offsetPointer is 24 strides ahead of pointer


注意: Swift がデータ型と値のサイズを計算する方法の詳細については、データ型サイズの計算 を参照してください。


データ型サイズの計算


C では、sizeof および alignof 演算子は任意の変数またはデータ型のサイズと配置を返します。Swift では、MemoryLayout<T> を使用して、size、stride、 および alignment プロパティを通じて、パラメータ化された型 T のメモリレイアウトにアクセスします。たとえば、Darwin の timeval 構造体は、16 の size と stride があり、8 の alignment を持っています。


    << SWIFT >>

  1. print(MemoryLayout<timeval>.size)
  2. // Prints "16"
  3. print(MemoryLayout<timeval>.stride)
  4. // Prints "16"
  5. print(MemoryLayout<timeval>.alignment)
  6. // Prints "8"


これは、型または値のサイズを引数として持つ Swift から C 関数を呼び出すときに使用します。たとえば、 setsockopt(_:_:_:_:_:) 関数は、その値へのポインタとその値の長さを渡すことによって、ソケットの受信タイムアウトオプション(SO_RCVTIMEO) として timeval の値を指定できます。


    << SWIFT >>

  1. let sockfd = socket(AF_INET, SOCK_STREAM, 0)
  2. var optval = timeval(tv_sec: 30, tv_usec: 0)
  3. let optlen = socklen_t(MemoryLayout<timeval>.size)
  4. if setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &optval, optlen) == 0 {
  5.         // ...
  6. }


詳細については、MemoryLayout を参照してください。



1回限りの初期化


C では、POSIX の pthread_once() 関数と Grand Central Dispatch の dispatch_once() 関数と dispatch_once_f() 関数は、初期化コードを正確に1回実行するためのメカニズムを提供します。Swift では、グローバル定数と格納された型プロパティは、複数のスレッドで同時にアクセスされた場合でも、1度だけ初期化されることが保証されています。この機能は言語機能によって提供されるため、対応する POSIX および Grand Central Dispatch の C 関数呼び出しは Swift によって公開されません。


プリプロセッサの指令


Swift コンパイラはプリプロセッサを含みません。代わりに、コンパイル時属性、条件付きコンパイルブロック、および言語機能を利用して、同じ機能を実現します。このため、プリプロセッサの指令は Swift に import されません。


簡単なマクロ


#define ディレクティブ(指令) を典型的に使って C と Objective-C の原始定数を定義する所は、Swift では代わりにグローバル定数を使用します。たとえば、定数定義 #define FADE_ANIMATION_DURATION 0.35 は、Swift では let FADE_ANIMATION_DURATION = 0.35 としてうまく表現できます。単純な定数のようなマクロは Swift のグローバル変数に直接マッピングされるため、コンパイラは C および Objective-C ソースファイルで定義された単純なマクロを自動的に import します。


複雑なマクロ


複雑なマクロは、C および Objective-C で使用されますが、Swift には対応するものがありません。複雑なマクロは括弧で囲まれた、関数のようなマクロを含む定数を定義していないマクロです。型チェック制約を回避するために、または定型コードを大量に再入力しなくて済むように、C と Objective-C では複雑なマクロを使用します。しかし、マクロはデバッグやリファクタリングを困難にします。Swift では、妥協せずに同じ結果を達成するための関数や汎用の物を使用できます。したがって、C と Objective-C のソースファイル内にある複雑なマクロは、あなたの Swift コードでは利用できません。



条件付きコンパイルブロック


Swift のコードと Objective-C のコードは条件付きで、異なる方法でコンパイルされます。Swift のコードは、条件付きコンパイルブロック を使用して条件付きでコンパイルできます。たとえば、以下のコードを swift -D DEBUG_LOGGING を使用してコンパイルして DEBUG_LOGGING 条件付きコンパイルフラグを設定した場合、コンパイラは条件付きコンパイルブロックの本体にコードを含めます。


    << SWIFT >>

  1. #if DEBUG_LOGGING
  2. print("Flag enabled.")
  3. #endif


コンパイル条件 は、リテラルの true 値と false 値、カスタムの条件付きコンパイルフラグ(-D <#flag#> を使用して指定)、および以下の表にリストしたプラットフォーム条件を含めることができます。


関数有効な引数
os()macOS, iOS, watchOS, tvOS, Linux
arch()x86_64, arm, arm64, i386
swift()>= バージョン番号が続く


注意: ARM 64 デバイスでは、arch(arm) プラットフォームの条件は true を返しません。32 ビットの iOS シミュレータ用にコードをコンパイルすると、arch(i386) プラットフォームの条件は true を返します。


&& および || 演算子を使用してコンパイル条件を組み合わせることができ、! 演算子で、それらを否定し、また #elseif#else のコンパイル指示文で分岐を追加できます。また、条件付きコンパイルブロックは、他の条件付きコンパイルブロック内に入れ子にもできます。


    << SWIFT >>

  1. #if arch(arm) || arch(arm64)
  2. #if swift(>=3.0)
  3. print("Using Swift 3 ARM code")
  4.         #else
  5.         print("Using Swift 2.2 ARM code")
  6. #endif
  7. #elseif arch(x86_64)
  8. print("Using 64-bit x86 code.")
  9. #else
  10. print("Using general code.")
  11. #endif


C のプリプロセッサの条件コンパイルとは対照的に、Swift での条件付きコンパイルブロックは、自己完結型で構文的に有効なコードのブロックを完全に囲まなければなりません。これは、すべての Swift コードがコンパイルされていなくても構文チェックされているためです。ただし、コンパイル条件が swift() プラットフォーム条件を含んでいる場合は例外があります。Swift のコンパイラのバージョンがプラットフォーム条件で指定されたものと一致する場合のみ、文が解析されます。この例外は、古いコンパイラが Swift の新しいバージョンで導入された構文を解析しようとしないことを保証します。





前:Cocoa デザインパターンの採用 次:同じプロジェクトでの Swift と Objective-C
目次
Xcode の新機能

Swift:はじめに
Swift Programming Language
Swift Blog より

  • はじめに(Part I)
  • 基本設定
  • Swift 環境の設定
    Swift のインポートプロセスの理解
  • 相互運用性(Part II)
  • Objective-C API との相互作用
  • 初期化
  • クラスファクトリメソッドとコンビニエンスイニシャライザ
    失敗可能な初期化
    プロパティへのアクセス
    メソッドでの作業
  • id の互換性
  • Any のダウンキャスト
    動的なメソッドの参照
    認識されないセレクタと optional の連鎖
  • ヌル可能性 (Nullabity) と optionals
  • ヌル可能性のない (nonnullable) オブジェクトに Optional をブリッジする
    プロトコルで修飾されたクラス
    軽量級の汎用
    拡張機能
  • クロージャ
  • self をキャプチャする時の強い循環参照を回避する
  • オブジェクトの比較
  • Hash する
  • Swift の型の互換性
  • Objective-C で Swift インターフェースの構成
    動的な送出を要求
  • セレクタ
  • Objective-C メソッドの安全でない呼び出し
    キーとキーパス
  • Swift のクラスとプロトコルの書き方及び Objective-C の動作
  • Objective-C のクラスからの継承
  • NSCoding
    プロトコルの採用
    イニシャライザとデイニシャライザを書く
    Objective-C API で Swift クラス名を使用する
  • Interface Builder との統合
  • アウトレットとアクションを使った作業
    ライブレンダリング
  • プロパティ属性の指定
  • Strong と Weak
    読み/書き可能と読み取り専用
    コピーの意味
    コアデータ管理オブジェクトサブクラスの実装
    プロトコルの宣言
  • Cocoa フレームワークでの作業
  • Foundation
  • ブリッジ型
  • 名前の変更された型
  • 文字列

    配列
    セット
    Dictionary
  • Core Foundation
  • 再マッピングされた型
    メモリ管理オブジェクト
    管理されないオブジェクト
    統合ログオン
    Cocoa 構造体
  • Cocoa デザインパターンの採用
  • デリゲート化
    遅延した初期化
  • エラー処理
  • エラーの catch と処理
    エラーを Optional の値に変換する
    エラーを throw する
    カスタムエラーの Catch と処理
    キー値の監視
    ターゲット・アクション
    シングルトン
    Introspection(内省)
  • 連載
  • ローカライズ
    自動解放プール
    API の利用
    コマンドライン引数の処理
  • C の API との相互作用
  • 原始的な型
  • グローバル定数
  • import された定数の列挙体と構造体
  • 関数
  • 可変個引数の関数
  • 構造体
  • 型メンバとして関数を import
    列挙型
    Option のセット
    ユニオン
    ビットフィールド
    名前のない構造体と union のフィールド
  • ポインタ
  • 定数ポインタ
    可変ポインタ
    自動解放ポインタ
    関数ポインタ
    バッファポインタ
    ヌルポインタ
    ポインタの計算
    データ型サイズの計算
    1回限りの初期化
  • プリプロセッサの指令
  • 簡単なマクロ
    複雑なマクロ
    条件付きコンパイルブロック
  • うまく組み合わせる(part III)
  • 同じプロジェクトでの Swift と Objective-C
  • 「うまく組み合わせる」概観
  • 同じアプリターゲット内からコードを import
  • Objective-C から Swift への import
    Swift から Objective-C への import
  • 同じフレームワークターゲット内からコードを import
  • Objective-C から Swift への import
    Swift から Objective-C への import
    外部フレームワークの import
  • Objective-C からの Swift の使い方
  • Objective-C ヘッダでの Swift クラスまたはプロトコルの参照
    Objective-C クラスで採用可能な Swift プロトコルを宣言
    Objective-C の実装での Swift プロトコルの採用
    Objective-C から使用できる Swift のエラー型の宣言
  • Objective-C インターフェイス用に Swift 名をオーバーライド
  • クラスファクトリメソッド
    列挙型
    Objective-C 宣言を洗練する
    Swift で Objective-C インターフェイスを使用できないようにする
    Objective-C API へ利用可能性情報の追加
    プロダクトモジュールの命名
    トラブルシューティングのヒントと注意
  • 移行(Part IV)
  • Objective-C から Swift への移行
  • 移行のための Objective-C コードの準備
  • 移行プロセス
  • はじめる前に
    作業中に
    見終わったら
    トラブルシューティングのヒントと注意
  • 更新履歴
  • マニュアルの更新履歴












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)