#author("2016-06-09T04:20:08+00:00","default:nitta","nitta")
#author("2016-06-09T04:20:35+00:00","default:nitta","nitta")
[[Swift]]

*Swift/C&Objective-Cとのデータの受け渡し [#f2b4195a]

**データ型の互換性 [#u96f3bb1]

***C言語の単純型とSwiftの型 [#ta5f8129]
|C言語の単純型|Swiftの型|
|char, signed char|Int8, CChar|
|unsigned char|UInt8, CUnsignedChar|
|short|Int16, CShort|
|unsigned short|UInt16, CUnsignedInt|
|int|Int32, CInt|
|unsigned int|UInt, CUnsignedInt|
|long|Int, CLong|
|unsigned long|UInt, CUnsignedLong|
|long long|Int64, CLongLong|
|unsigned long long|UInt64, CUnsignedLongLong|
|wchar_t|UnicodeScalar, CWideChar|
|char16_t|UInt16, CChar16|
|char32_t|UnicodeScalar, CChar32|
|float|Float, CFloat|
|double|Double, CDouble|


C援護の関数 pow, sqrt の例(Foundationのモジュールのimportが必要)
 func powf(_: Float, _: Float) -> Float
 func pow(_: Double, _: Double) -> Double
 
 func sqrtf(_: Float) -> Float
 func sqrt(_: Double) -> Double

***C言語のポインタとSwiftの型 [#y53bf5da]

APIを経由してひとまとまりのデータの受け渡しを行う場合は、
Swiftで配列を用意しておき、その配列への「ポインタ」をCの関数に渡して
値を読み書きしてもらう方法が一般的。

ポインタには nil を代入でき、演算子 ==, != を用いてポインタとnilと比較することもできる。

|種類|C言語の型|Swiftの型|
|ポインタ|const T*|Unsafe&#80;ointer<T>|
|~|T*|Unsafe&#77;utable&#80;ointer<T>|
|~|void*|Unsafe&#77;utable&#80;ointer<Void>|
|クラスTのインスタンス|const T*|Unsafe&#80;ointer<T>|
|~|_strong T*|Unsafe&#77;utable&#80;ointer<T>|
|~|T**|Autoreleasing&#85;nsafe&#77;utable&#80;ointer<T>|
|関数|T (*func)(U)|@convention(c)(U)->T|
|~|T (*func)(void)|@convention(c)() -> T|
|ブロック|T (^block)(U)|@convention(block)(U)->T|
|空ポインタ| nil/NULL|(任意のポインタ型)nil|

型の名称に Unsafe がついているのはメモリ管理を ARC で行っていないことを表している。
これらを Unsafe Pointer と呼ぶことにする。

Mutable は、ポインタが指すメモリ領域に書き込んで変更できることを表す。

***変数を用意して関数の結果を書き込む [#c3bbad4d]

 func time(_: UnsafeMutablePointer<time_t>) -> time_t
 func localtime_r(_: UnsafePointer<time_t>,_:UnsafeMutablePointer<tm>) -> UnsafeMutablePointer<tm>

 import Darwin
 var current = time(nil)   // current は time_t 型になる

ポインタには「変数のポインタを渡す」場合と「配列の先頭要素を渡す」場合がある。
変数のポインタを渡す場合は、実引数として "&" をつけた変数を記述する(inout 演算子がついた引数に渡す場合と同様)。

 var current: time_t = time_t()    // 変数を用意して初期化
 time(&current)                    // 変数 current に値が書き込まれる

 import Darwin   // Foundation でもよい
 var current : time_t = time(nil)   // 現在時刻を time_t 型で取得
 var tnow = tm()                    // 変数を用意して初期化
 localtime_r(&current, &tnow)       // 変数 tnow に情報が書き込まれる
 print("\(tnow.tm_mon + 1)月\(tnow.tm_mday)日")  // 本日の日付が表示される

***配列を用意して関数の結果を書き込む [#p36bd33d]

time_t型データから、日時を表す文字列を生成する ctime_r 関数を使ってみる。
第1引数は time_t型へのポインタで、第2引数が文字列領域へのポインタである。
C 言語の char 型は Swift では Int8 型なので
文字列領域へのポインタは Unsafe&#77;utable&#80;ointer<Int8> となる。

 func ctime_r(_: UnsafePointer<time_t>, _: UnsafeMutablePoiner<Int8>) -> UnsafeMutablePointer<Int8>

配列のポインタを関数に渡す場合、使い方は次の2通り。
-渡した配列の内容を関数で変更する場合。配列名に "&" を付けて渡す。
-渡した配列の内容を関数で変更しない場合。配列名に "&" を付ける必要はない。

 import Darwin
 var buf = (Int8)(count: 26, repeatedValue: 0)   // 26個の0
 var current: time_t = time(nil)
 ctime_r(&current,&buf)                          // 文字列がbufに得られる
 puts(buff)                          // 現在時刻が表示される
 // puts(&buff)    // &をつけても同じ結果が得られる

変数bufの値は Swift の String 型ではないので、表示するのに print 関数は使えない。
C言語の puts を使うことはできる。
putsではポインタの内容を変更しないので、putsに与える実引数には & をつけても
つけなくてもどちらでも同じ動作となる。

 var tt = [time(nil) ]    // time_t 型の配列を作り、第1要素を初期化する
 ctime_r(tt,&buf)         // &tt でも動作する

ポインタへの値の渡し方
||Unsafe&#80;ointer<T> ~ 読み取り専用|Unsafe&#77;utable&#80;ointer<T> ~ 読み書き可能|
|値が1つの変数 x:T|&#38;x|&#38;x|
|配列 a:[T]|aまたは&#38;a|&#38;a|

***C言語ポインタ引数に関するルール [#o68075c4]

Swift でC言語の fopen関数を使ってファイルをオープンするコード
 let fpin = fopen(path,"r")   // 引数はSwiftの String 型
 
関数 fopen の Swift インタフェース
 func fopen(_: UnsafePointer<Int8>, _: UnsafePointer<Int8>) -> UnsafeMutablePointer<FILE>

String型と Unsafe&#80;ointer<Int8> 型は互換ではない。
C言語のAPIを用いてSwiftを動作させるために、ポインタ引数については特別ルールがある。
+関数の引数が Unsafe&#80;ointer<T> 型で定義されているとき、次の型の実引数を受け取ることができる。
--nil
--Unsafe&#80;ointer<T>
--Unsafe&#77;utable&#80;ointer<T>
--Autoreleasing&#85;nsafe&#77;utable&#80;ointer<T>
--T型の引数に & を付けたもの (inoutが指定された引数と同様)
--T型の値。配列の先頭として渡され、配列は呼び出しが終わるまで保持される。
&はつけてもつけなくても動作する。配列リテラルで渡すこともできる。
--String。ただし、Tは Int8 か UInt8 の場合。
文字列はバッファ内で UTF-8 に変換され、バッファは呼び出しが終わるまで保持される。
+配列の引数が Unsafe&#80;ointer<Void> 型で定義されているとき、任意の型 T の
ポインタ Unsafe&#80;ointer<T> について、上記1.で受取可能とした実引数を指定できる。
+関数の引数が Unsafe&#77;utable&#80;ointer<T> 型で定義されているとき、
次の型の実引数を受け取ることができる。
--nil
--Unsafe&#77;utable&#80;ointer<T>
--T型の書き込みが可能な変数に &#38; をつけたもの。
--[T]型の書き込みが可能な変数に &#38; をつけたもの。
+関数の引数が Unsafe&#77;utable&#80;ointer<Void> 型で定義されているとき、
任意の型 T のポインタ Unsafe&#77;utable&#80;ointer<T> について、上記3.で
受取可能とした実引数を指定できる。

このルールにより Swift の String 型を C 言語の文字列のように渡すことができているが、
逆はできない。

引数として Unsafe&#80;ointer<T> を受け取るC言語の関数に
Unsafe&#77;utable&#80;ointer<T>
を渡しても動作する。しかし、
Swift では Unsafe&#77;utable&#80;ointer<T>
と Unsafe&#80;ointer<T> は異なる型なので、
型の変換を明示する必要がある。

 let p: UnsafeMutablePointer<Int8> =  /* 何かの値 */
 let q: UnsafePointer<Int8>(p)        // ポインタの型を変換する
 let z: UnsafePointer<Int8> = p       // エラー。Swiftではこの代入はできない。

unsafe pointer 間での相互変換は自由にできる。
つまり、T型とU型が無関係であっても
Unsafe&#80;ointer<T>
を
Unsafe&#80;ointer<U>
に、
Unsafe&#77;utable&#80;ointer<T>
を
Unsafe&#77;utable&#80;ointer<U>
に変換できる。どちらの型も2つのイニシャライザを持っている。
 init<U>(_ from: UnsafeMutablePointer<U>)
 init<U>(_ from: UnsafePointer<U>)
型パラメータ U には何の制限もないので、次のような変換も可能である。
 let p: UnsafePointer<Int8> = /* char 型を読み出し可能な何らかのポインタ */
 let q = UnsafeMutablePointer<Int32>(p) = /* 整数値を書き込み可能なポインタ */
 
*** 渡されたポインタから値 を取り出す [#xfc6cdaa]

リエントラント(再入可能)でスレッドセーフな関数は名前の末尾に &#95;r がついている。
元々 Unixで用意されていた関数は localtime, ctime でありリエントラントではない。
これらを Swift から利用してみる。

 func localtime(_: UnsafePointer<time_t>) -> UnsafeMutablePointer<tm>
 func ctime(_ UnsafePointer<time_t>) -> UnsafeMutablePointer<Int8>

3種類の unsafe pointer は Swift では構造体として定義されており、
ポインタの指す内容にアクセスするプロパティ memory と、
参照しているメモリを先頭から配列のように参照できる添字付けの機能を提供している。

 // UnsafeMutablePointer<T> 型の場合
 var memory: T { get nonmutating set }
 subscript (i: Int) -> T { get nonmutating set }

Unsafe&#77;utable&#80;ointer<T> は C 言語の (T*) 型に相当する。
これらの型をもつ変数 p の値にアクセスするには、C言語では *p と、
Swift では p.memory と記述する。
ポインタの位置からデータ n 個分先のデータにアクセスするには
C言語でもSwiftでも p[n] と記述する。

 // unsafe pointer に直接アクセスする例
 import Darwin
 var current = time(nil)
 let jnow: tm = localtime(&current).memory   // 構造体をコピーして代入する
 print("\(jnow.tm_mon + 1)月\(jnow.tm_mday)日")
 let p = ctime(&current)      // pは UnsafeMutablePointer<Int8>型
 
 for i in 0..<25 {            // 添字を使って文字にアクセスする例
   putchar(Int32(p[i]))       // putcharの引数はint型(Int32型)
 }                            // 最後の文字は改行文字
 
 var ptr = p                  // ポインタを進めながら文字にアクセスする例
 for i in 0..<25 {
   putchar(Int32(ptr.memory)) // ポインタの指すデータを表示する
   ptr = ptr.successor()      // ポインタを1つ進める
 }

Swift ではポインタを直接変数に代入することはできないので、定数jnow には tm 型の構造体の
コピーが代入される。

***ポインタから文字列への変換 [#b1fbe9a0]
String型のタイプメソッドを使う。
 static func fromCString(_: UnsafePointer<CChar>) -> String?

 let p = ctime(&current)      // pはUnsafeMutablePointer<Int8>型
 if let s = String.fromCString(p) {  // オプショナル束縛構文
   print(s)
 }

Foundation を import している場合、String型に対して次のイニシャライザが利用可能である。
文字列が UTF-8 でなかった場合は nil が返される。
 init?(UTFString: UnsafePointer<CChar>)

***コマンドラインの引数にアクセスする。 [#oe827b2a]

コマンド引数にアクセスするために、列挙型 Process が定義されていて、
タイププロパティを使って引数リストにアクセスできる。

 static let arguments: [String]
 static var argc: CInt { get }
 static var unsafeArgv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>> { get }

 var i = 0
 for elm in Process.arguments {
   print("\(i++): \(elm)")
 }

***Unsafe&#66;uffer&#80;ointer<T>を利用する [#ef1e93f0]
unsafe pointer には添字でアクセスする方法以外に、
プロトコル Collection&#84;ype に適合している
構造体 Unsafe&#66;uffer&#80;ointer<T>
を利用する方法もある。

 uptr: UnsafePointer<Int> = /* 略 */
 let array = UnsafeBufferPointer<Int>(start: uptr, count: 100) // 先頭から100個分のInt型

*** T**型の引数の扱い [#a280dc53]

-TがC言語の単純型の場合~
C言語の T** は Swift では
Unsafe&#77;utable&#80;ointer<Unsafe&#77;utable&#80;ointer<T>>
となる。
-TがObjective-Cのクラスの場合~
Objective-Cでは、メソッドに渡される T** 型は
「クラス T のインスタンスを格納するローカル変数へのポインタ」
または「nil」であり、グローバル変数や配列であってはならない。
Swift側からObjective-C側にポインタを渡すとき(ローカル変数でなくても構わないが)
T**型を
Autoreleasing&#85;nsafe&#77;utable&#80;ointer<T>
として扱う。すなわち、渡されたポインタがnilでなければ、クラスTのインスタンスが
一時的に作成されて利用され、関数の終了時にポインタが指す先にコピーされる。

*対応付けられたデータ型 [#y2bc011f]

**数値と数値オブジェクト [#w71c7462]
Objective-C の NSInteger と NSUInteger はどちらも
Swift の Int 型に対応付けられる。

Objective-C のインタフェースで NSNumber のインスタンスが使われる部分には
Swift の Int, UInt, Float, Double, Bool 型のインスタンスがに
対応付けられる。
 var n: NSNumber = 10.25
 print(n as Float)    // 10.25 が表示される
 print(n as Int)      // 10 が表示される

**オブジェクト [#w280a0c8]
Swift には AnyObject 型があり、任意のクラスのインスタンスに対応付けられる。

Foundation を import してあれば、Objective-C のクラスに対応付けられた型は
全て Swift の AnyObject に対応付けることが可能である。

C++ のオブジェクトは Swift では利用できない。

**文字列 [#ka0b82d6]

Swift のString 型と
Objective-C のNSString型は
対応付けられている。

String型には NSString のメソッドを適用できるが、逆はできない。

 var s: String = "protects the knowledge of the strong"
 print(s.rangeOfString("owl")!)   // 15..<18 が表示される。
 s = "クロネコ\u{1F431}"           // 顔文字を含む
 print((s as NSString).length)    // 6 が表示される
 var m = NSMutableString(string: "小鳥\u{1F426}")
 s = m as String
 // var mm = s as NSMutableString   // エラー。このキャストは不加能。

NSString型は UTF16 を用いて Unicode を扱っているため、
顔文字などが含まれる文字列の長さを1つずつ多く間違えてしまうという問題がある。
NSStringのほとんどの機能は Foundation を import すれば String 型から使えるので
NSString型に変換して機能を利用する必要はない。

Swift の String 型と Objective-C の NSMutable&#83;tring 型は対応付けられていないので、
互いに自由に変換はできない。
ただし、NSMutable&#83;tring型は NSString型のサブクラスなので、String型に変換することはできない。

NSString はクラスクラスタなので、実際の型が NSString であるとは限らない。

** 配列と集合 [#g176deb5]

Swift の Array 型と Objective-C の NSArray 型は対応付けられており、
NSArray 型で型パラメータを指定しない配列オブジェクトは
Swift の [ Any&#79;bject ] という型に対応付けられる。

 let ns1: NSArray = [ 152.0, 4, UInt(1) ]
 let ar1 = ns1                            // [ AnyObject ] 型になる
 let ar2 = ns1 as! [Int]                  // [ Int ] 型にできる
 print(ar2)               // [ 152 4 1 ] が表示される
 let dat:[Int] = [ 161, 152, 160, 153 ]
 let ns2: NSArray = dat       // NSNumber* の配列になる

as! で型変換した場合、キャストできない要素があると実行時エラーになる。
as? で型変換した場合は、キャストできない要素があると nil が返される。

Objective-C から渡された [ Any&#79;bject ]型の配列の要素がそれぞれ異なる型の場合、
たとえば文字列だけを取り出したい場合は次のようにクロージャを利用する。

var array: [ AnyObject] = /* NSArray型 */
 let strs = array.filter{ $0 is String }


集合型では、
Swift の Set 型と
Objective-C の NSSet 型が対応付けられている。
Swiftの Set 型の要素はプロトコル Hashable に適合している必要がある。

**辞書 [#m7887f66]

Swift の Dictionary 型と、Objective-C の NSDictionary は対応付けられている。
型パラメータを指定しない場合 Swift の
[ NSObject : Any&#79;bject ]
という型となる。

 let info: NSDictionary = [ "Height" : 161.0, "Grade" : 2, "Level" : 5 ]
 let pinfo = info as! [String:Int]   // このキャストは可能。
 print(pinfo)   // [ "Height": 161, "Grade" : 2, "Level" : 5 ] が表示される

一般に Objective-C から渡される辞書には複数の型が含まれているので、
ダウンキャストには as? 演算子を用いるか、要素毎に個別に対応した方がよい。

 for (key, value) in info {
   if let k = key as? String, v = value as? Int {  // [String:Int]な要素だけを扱う
     print(k + ": ", v)
   }
 }
または
 for enry in info {
   if case let (k as String, v as Int) = entry {  // (String, Int)だけを扱う
     print(k + ": ", v)
   }
 }


**NSValue と CoreGraphics の構造体 [#xc085fab]
CFLoat型はDoubleの場合とFloatの場合があるので、
Objective-Cでは自動型変換で大丈夫であっても、
Swiftではエラーとなることがある。
イニシャライザを使って明示的に型変換を行うとよい。
 var xp: CFLoat = CGFloat(sin(th))    // sin() の返り値はDouble
 var x2: Double = Double(xp * xp)

Core&#71;raphics で定義されている構造体
||データ型|Foundationの名称|プロパティ|
|点の座標|CGPoint|NSPoint|var x:CGFLoat|
|~|~|~|var y:CGFloat|
|縦横の大きさ|CGSize|NSSize|var width:CGFloat|
|~|~|~|var height: CGFloat|
|長方形領域|CGrect|NSRect|var origin:CGPoint|
|~|~|~|var size:CGSize|

Swiftでは Objective-C で使われている CGPoint, CGSize, CGRect 構造体をそのまま
利用できる。

**NSData [#p2510913]
Objective-C の NSData に対応づけられた Swift の型はないので、
[Int8] 型、または [UInt8] 型でバイト列のデータをやりとりする。

Objective-C から受け取ったNSDataからデータを読み出すには、プロパティ bytes か、
メソッド getBytes を使うとよい。
 var bytes: UnsafePointer<Void> { get }
 func getBytes(_: UnsafeMutablePointer<Void>, length: Int)

Swift で NSData のインスタンスを作ることができる。2番目のイニシャライザはデータをコピーせず共有する。
 init(bytes: UnsafePointer<Void>, length: Int)
 init(bytesNoCopy: UnsafePointer<Void>, length: Int)

**データのバイト数を調べる [#dc4a0622]

Swift では、型名を指定してバイト数を得る sizeof() 関数、
変数や値を指定してそのバイト数を得る sizeofValue() 関数。

 sizeof(Int)            // 8 (64bitマシンの場合)
 sizeof((Int8,Int8))    // 2
 sizeofValue(3.14)      // 8

パディングを考慮した値を得るには strideof() と strideofValue() 関数を使う。
 strideof(Float80)                  // 16
 strideofValue(["Cinderella":346])  // 8

**Core Foundation [#g928876d]

Foundation を import すると Core Foundation も import されている。
Core Foundation のオブジェクトを表す型名は
CFArray&#82;ef , CFURLRef のように
参照型であることを示す Ref がついているが、Swiftでは
「Ref のある型名」も「Refのない型名」も両方使える。
Core Foundation の CFTypeRef 型は Swift の AnyObject 型として扱われる。

Core Foundation の型には toll-free (型変換なしにObjective-Cで相互利用できる)
なものがあるが、これは Swift でも利用できる。

|BGCOLOR(#0000ff): Core Foundation|BGCOLOR(#0000ff): Objective-C (Foundation)|
|CFArray&#82;ef|NSArray|
|CFMutable&#65;rray&#82;ef|NSMutable&#65;rray|
|CFData&#65;ef|NSData|
|CFMutable&#68;ata&#65;ef|NSMutable&#68;ata|
|CFDate&#65;ef|NSDate|
|CFDicitonary&#65;ef|NSDictionary|
|CFMutable&#68;ictionary&#65;ef|NSMutable&#68;ictionary|
|CFString&#65;ef|NSString|
|CFMutable&#83;tring&#65;ef|NSMutable&#83;tring|
|CFNumber&#65;ef|NSNumber|
|CFURL&#65;ef|NSURL|


*列挙型とその他のデータ [#fef5e6c7]

**列挙型 [#sdd845b9]

C言語やObjective-Cにおける列挙型は整数型とあまり明確な区別はなかったが、
次のどの形式で定義されたかによって Swift からの見え方が異なる。

-型名のある列挙型
-型名のない列挙型
-NS_ENUM マクロで定義された列挙型
-NS_OPTIONS マクロで定義された列挙型

***型名のある列挙型 [#e1ef52f4]
 enum AIMAbility {
   AIMAccelerator = 1,
   AIMDarkMatter,
   AIMElectromaster
 };

Swift向けのインタフェースは次のような構造体として定義される。
プロトコル RawRepresentable はこの型が実体を持つことを表わし、
プロパティ rawValue が各要素の値を返す。

 public struct AIMAbility : RawRepresentable, Equatable {
   public init(_ rawValue: UInt32)
   public init(rawValue: UInt32)
   public var rawValue: UInt32
 }
 public var AIMAccelerator : AIMAbility { get }
 public var AIMDarkMatter : AIMAbility { get }
 public var AIMElectromaster : AIMAbility { get }

***型名のない列挙型 [#b62e425d]
 enum { Male, Female }

この場合、Swiftの宣言ではメンバ名自体が Int 型の定数になり、構造体は構成されない。

 public var Male: Int { get }
 public var Female: Int { get }

***マクロ NS_ENUM で定義された列挙型 [#p1a52eb2]

略

***マクロ NS_OPTIONS で定義された列挙型 [#w8a1a4af]

略

***マクロ定義 [#xdfa8c3f]

CやObjective-Cで定義された定数値を表す単純なマクロは、
Swift ではグローバルな定数として表現される。

 #define WLRegulation  1.048596    // Objective-Cのマクロ定義

 let WLRegulation = 1.048596       // Swift のグローバルな定数

引数を持つ関数マクロは、Swiftには情報として取り込まれることはない。

**共用体とビットフィールド [#y39b33b3]

Swift では、通常の方法ではC言語の共用体のようなデータ構造は定義できないが、
そのようなデータにアクセスしたり、新しいインスタンスを生成したりすることは可能である。

 typedef union IntChars {    // C言語における共用体の定義
   int i;
   unsigned char c[4];
 } IntChars;

 public struct IntChars {    // 上記の共用体に対応する Swift のインタフェース
   public var i: Int32
   public var c: (UInt8, Uint8, Uint8, Uint8)
   public init(i: Int32)
   public init(c: (UInt8, Uint8, Uint8, Uint8))
   public init()
 }

ビットフィールドについても同様である。

 struct WNumber {     // C言語におけるビットフィールド
   unsigned int flag:1    // 1 bitのみのフィールド
   unsigned int pad:7,    // 7 bitのみのフィールド
   IntChars data;         // 共用体
 }

 public struct WNumber {  // 上記のビットフィールドに対応するSwiftのインタフェース
   public var flag: UInt32
   public var pad: UInt32
   public var data: IntChars
   public init()
   public init(flag: UInt32, pad: UInt32, data: IntChars)
 }


**各国語対応の文字列を得る [#yf9182e2]

Foundationの関数NSLocalizedString()を利用する。
 func NSLocalizedString(key: String,
     tableName: String? = default,   // 省略時は Localizable.strings
        bundle: NSBundle = default,  // 省略時は メインバンドル
	 value: String = default,    // 省略時は nil
       comment: String) -> String

例
 let mesg = func NSLocalizedString("Welcome", comment:"起動メッセージ")
日本語リソースの Localizable.strings に "Welcome" = "ようこそ" という
登録があれば、日本語を取り出せる。
 

**関数ポインタ [#x18fd08f]

Objective-C の関数へのポインタは、Swiftでは
 @convention(c) T
として扱う。Tは関数を表す型で、たとえば「()->Int32」。

@convention(c) 属性によって、
「この関数がC言語の関数へのポインタであり、
Swiftのクロージャのように環境から値をキャプチャすることはない」
ことを示している。

C言語のAPIに関数ポインタとして渡すことができるのは、
-Swiftのトップレベルの関数
-クロージャのリテラル
-nil
のどれかである。
この条件を満せば、SwiftのクロージャとCの関数へのポインタは同じものとして扱うことができる。

 void qsort(void *base, size_t nel, size_t width, int(*compar)(const void *, const void *));

 typealias Episode = (String, Int)
 var buf:[Episode] = [ ("Parade",10), ("Baltazar", 5), (Pacusi", 1) ]
 qsort(&buf,buf.count,strideof(Episode)){
   (x:UnsafePointer<Void>, y:UnsafePointer<Void>) -> Int32 in
   let s: Episode = UnsafePointer<Episode>(x).memory
   let r: Episode = UnsafePointer<Episode>(y).memory
   return Int32(s.1 - r.1)
 })
 print(buf)  // [ (Pacusi", 1),  ("Baltazar", 5), ("Parade",10) ] が表示される


**C言語のブロックオブジェクト [#ea3ffd2c]
Objective-C で定義されたブロックオブジェクトを Swift に渡して処理を行わせることができる。

Tはブロックオブジェクトの引数と返り値を表す型であり、たとえば「() -> Int32」。
 @convention(block) T

 int scale = 15;
 [calc setScaleBlock:^(int n) {
   return n * scale;
 }];

このブロックオブジェクトは、swiftでは次のような型の変数に格納できる。
外側の括弧がないと型の解釈があいまいになることに注意(typealias宣言を使って別の名前をつけるとよい)。

 var block: (@convention(block) (Int32) -> Int32) !

変数 block は Swift のクロージャであるかのように、引数を渡して実行が可能。
実行時には渡されるときにキャプチャした値(scale = 15)が使われる。

*Null許容性 (nullability) [#ibc37bcc]

Swiftのオプショナル型は変数がインスタンスを参照する場合としない場合(nil)を区別して扱うためのものであるが、
Objective-Cではあまり区別していなかった。
このようなObjective-Cの特性を扱うために導入された概念が Null 許容性 (nullability) である。
-NULL (または nil) でもよい場合 -- Null許容 (nullable)
-NULL (または nil) ではいけない場合 -- Null非許容 (nonnulable)

Objective-C の Null 許容性の表現

- _Nullable --- Null許容。値が NULL や nil の場合がある。
- _Nonnull --- Null非許容。値が NULL や nil の場合はない。
- _Null_unspecified --- 指定なし。値が NULL や nil の場合がある。

クラス UIImage のクラスメソッド + imageWithData: は引数に関しては Null非許容であり、返り値は Null許容である。
 + (UIImage * _Nullable) imageWithData: (NSData * _Nonnull) data;

型修飾子ではなく、キーワード nullable, nonnull, null_resettable(初期値にだけNULLやnilを許容する) も使うことができる。
 + (nullable UIImage *) imageWithData: (nonnull NSData *) data;

オプショナル型と Null 許容性の関係

|BGCOLOR(#0000ff): Objective-C|BGCOLOR(#0000ff): Swift|
|nonnull| 非オプショナル型 (T)|
|nullable|オプショナル型 (T?)|
|指定なし| 有値オプショナル型 (T!)|
|null_resettable| ~ |
|_Null_unspecified| ~ |

 //Objective-C
 @interface HestiaParty: Party
 @property (retain, nonnull) NSString *hero;
 @property (retain, nullable) NSString *helper;
 @property (retain, null_resettable) NSString *knife;
 @property (weak) NSString *supporter;
 + (nonnull instancetype) familia: (nullable NSString *) famous;
 + (nullable instancetype) initWithhero: (nonnull NSString *) hero;
 @end

 // Swift
 public class HestiaParty : Party {
   public var hero: String
   public var helper: String?
   public var knife: String!
   public var supporter: String?   // weakだと、インスタンスが開放されたときゼロ化される(nilになる)ので
   public class func familia(famouse: String?) -> Self
   public init?(hero: String)
 }

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS