Swift/dataTransfer
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
[[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 を代入でき、演算子 ==, != を用いてポイン...
|種類|C言語の型|Swiftの型|
|ポインタ|const T*|UnsafePointer<T>|
|~|T*|UnsafeMutablePointer<T>|
|~|void*|UnsafeMutablePointer<Void>|
|クラスTのインスタンス|const T*|UnsafePointer<T>|
|~|_strong T*|UnsafeMutablePointer<T>|
|~|T**|AutoreleasingUnsafeMutablePointer<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>,_:UnsafeMutabl...
import Darwin
var current = time(nil) // current は time_t 型になる
ポインタには「変数のポインタを渡す」場合と「配列の先頭要...
変数のポインタを渡す場合は、実引数として "&" をつけた変数...
var current: time_t = time_t() // 変数を用意して初期化
time(¤t) // 変数 current に値が...
import Darwin // Foundation でもよい
var current : time_t = time(nil) // 現在時刻を time_t ...
var tnow = tm() // 変数を用意して初期化
localtime_r(¤t, &tnow) // 変数 tnow に情報が...
print("\(tnow.tm_mon + 1)月\(tnow.tm_mday)日") // 本日...
***配列を用意して関数の結果を書き込む [#p36bd33d]
time_t型データから、日時を表す文字列を生成する ctime_r 関...
第1引数は time_t型へのポインタで、第2引数が文字列領域への...
C 言語の char 型は Swift では Int8 型なので
文字列領域へのポインタは UnsafeMutablePointer<Int...
func ctime_r(_: UnsafePointer<time_t>, _: UnsafeMutableP...
配列のポインタを関数に渡す場合、使い方は次の2通り。
-渡した配列の内容を関数で変更する場合。配列名に "&" を付...
-渡した配列の内容を関数で変更しない場合。配列名に "&" を...
import Darwin
var buf = (Int8)(count: 26, repeatedValue: 0) // 26個の0
var current: time_t = time(nil)
ctime_r(¤t,&buf) // 文字...
puts(buff) // 現在時刻が表示さ...
// puts(&buff) // &をつけても同じ結果が得られる
変数bufの値は Swift の String 型ではないので、表示するの...
C言語の puts を使うことはできる。
putsではポインタの内容を変更しないので、putsに与える実引...
つけなくてもどちらでも同じ動作となる。
var tt = [time(nil) ] // time_t 型の配列を作り、第1要...
ctime_r(tt,&buf) // &tt でも動作する
ポインタへの値の渡し方
||UnsafePointer<T> ~ 読み取り専用|UnsafeMutable&#...
|値が1つの変数 x:T|&x|&x|
|配列 a:[T]|aまたは&a|&a|
***C言語ポインタ引数に関するルール [#o68075c4]
Swift でC言語の fopen関数を使ってファイルをオープンするコ...
let fpin = fopen(path,"r") // 引数はSwiftの String 型
関数 fopen の Swift インタフェース
func fopen(_: UnsafePointer<Int8>, _: UnsafePointer<Int8...
String型と UnsafePointer<Int8> 型は互換ではない。
C言語のAPIを用いてSwiftを動作させるために、ポインタ引数に...
+関数の引数が UnsafePointer<T> 型で定義されているとき...
--nil
--UnsafePointer<T>
--UnsafeMutablePointer<T>
--AutoreleasingUnsafeMutablePointer<T>
--T型の引数に & を付けたもの (inoutが指定された引数と同様)
--T型の値。配列の先頭として渡され、配列は呼び出しが終わる...
&はつけてもつけなくても動作する。配列リテラルで渡すことも...
--String。ただし、Tは Int8 か UInt8 の場合。
文字列はバッファ内で UTF-8 に変換され、バッファは呼び出し...
+配列の引数が UnsafePointer<Void> 型で定義されている...
ポインタ UnsafePointer<T> について、上記1.で受取可能...
+関数の引数が UnsafeMutablePointer<T> 型で定義さ...
次の型の実引数を受け取ることができる。
--nil
--UnsafeMutablePointer<T>
--T型の書き込みが可能な変数に & をつけたもの。
--[T]型の書き込みが可能な変数に & をつけたもの。
+関数の引数が UnsafeMutablePointer<Void> 型で定義...
任意の型 T のポインタ UnsafeMutablePointer<T> に...
受取可能とした実引数を指定できる。
このルールにより Swift の String 型を C 言語の文字列のよ...
逆はできない。
引数として UnsafePointer<T> を受け取るC言語の関数に
UnsafeMutablePointer<T>
を渡しても動作する。しかし、
Swift では UnsafeMutablePointer<T>
と UnsafePointer<T> は異なる型なので、
型の変換を明示する必要がある。
let p: UnsafeMutablePointer<Int8> = /* 何かの値 */
let q: UnsafePointer<Int8>(p) // ポインタの型を変...
let z: UnsafePointer<Int8> = p // エラー。Swiftで...
unsafe pointer 間での相互変換は自由にできる。
つまり、T型とU型が無関係であっても
UnsafePointer<T>
を
UnsafePointer<U>
に、
UnsafeMutablePointer<T>
を
UnsafeMutablePointer<U>
に変換できる。どちらの型も2つのイニシャライザを持っている。
init<U>(_ from: UnsafeMutablePointer<U>)
init<U>(_ from: UnsafePointer<U>)
型パラメータ U には何の制限もないので、次のような変換も可...
let p: UnsafePointer<Int8> = /* char 型を読み出し可能な...
let q = UnsafeMutablePointer<Int32>(p) = /* 整数値を書き...
*** 渡されたポインタから値 を取り出す [#xfc6cdaa]
リエントラント(再入可能)でスレッドセーフな関数は名前の末...
元々 Unixで用意されていた関数は localtime, ctime でありリ...
これらを Swift から利用してみる。
func localtime(_: UnsafePointer<time_t>) -> UnsafeMutabl...
func ctime(_ UnsafePointer<time_t>) -> UnsafeMutablePoin...
3種類の unsafe pointer は Swift では構造体として定義され...
ポインタの指す内容にアクセスするプロパティ memory と、
参照しているメモリを先頭から配列のように参照できる添字付...
// UnsafeMutablePointer<T> 型の場合
var memory: T { get nonmutating set }
subscript (i: Int) -> T { get nonmutating set }
UnsafeMutablePointer<T> は C 言語の (T*) 型に相当...
これらの型をもつ変数 p の値にアクセスするには、C言語では ...
Swift では p.memory と記述する。
ポインタの位置からデータ n 個分先のデータにアクセスするには
C言語でもSwiftでも p[n] と記述する。
// unsafe pointer に直接アクセスする例
import Darwin
var current = time(nil)
let jnow: tm = localtime(¤t).memory // 構造体を...
print("\(jnow.tm_mon + 1)月\(jnow.tm_mday)日")
let p = ctime(¤t) // pは UnsafeMutablePointer...
for i in 0..<25 { // 添字を使って文字にアクセ...
putchar(Int32(p[i])) // putcharの引数はint型(Int...
} // 最後の文字は改行文字
var ptr = p // ポインタを進めながら文字...
for i in 0..<25 {
putchar(Int32(ptr.memory)) // ポインタの指すデータを表...
ptr = ptr.successor() // ポインタを1つ進める
}
Swift ではポインタを直接変数に代入することはできないので...
コピーが代入される。
***ポインタから文字列への変換 [#b1fbe9a0]
String型のタイプメソッドを使う。
static func fromCString(_: UnsafePointer<CChar>) -> Stri...
let p = ctime(¤t) // pはUnsafeMutablePointer<...
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<UnsafeMutabl...
var i = 0
for elm in Process.arguments {
print("\(i++): \(elm)")
}
***UnsafeBufferPointer<T>を利用する [#ef1e93f0]
unsafe pointer には添字でアクセスする方法以外に、
プロトコル CollectionType に適合している
構造体 UnsafeBufferPointer<T>
を利用する方法もある。
uptr: UnsafePointer<Int> = /* 略 */
let array = UnsafeBufferPointer<Int>(start: uptr, count:...
*** T**型の引数の扱い [#a280dc53]
-TがC言語の単純型の場合~
C言語の T** は Swift では
UnsafeMutablePointer<UnsafeMutablePointer...
となる。
-TがObjective-Cのクラスの場合~
Objective-Cでは、メソッドに渡される T** 型は
「クラス T のインスタンスを格納するローカル変数へのポイン...
または「nil」であり、グローバル変数や配列であってはならな...
Swift側からObjective-C側にポインタを渡すとき(ローカル変数...
T**型を
AutoreleasingUnsafeMutablePointer<T>
として扱う。すなわち、渡されたポインタがnilでなければ、ク...
一時的に作成されて利用され、関数の終了時にポインタが指す...
*対応付けられたデータ型 [#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 すれば St...
NSString型に変換して機能を利用する必要はない。
Swift の String 型と Objective-C の NSMutableString ...
互いに自由に変換はできない。
ただし、NSMutableString型は NSString型のサブクラスな...
NSString はクラスクラスタなので、実際の型が NSString であ...
** 配列と集合 [#g176deb5]
Swift の Array 型と Objective-C の NSArray 型は対応付けら...
NSArray 型で型パラメータを指定しない配列オブジェクトは
Swift の [ AnyObject ] という型に対応付けられる。
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 から渡された [ AnyObject ]型の配列の要素...
たとえば文字列だけを取り出したい場合は次のようにクロージ...
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 : AnyObject ]
という型となる。
let info: NSDictionary = [ "Height" : 161.0, "Grade" : 2...
let pinfo = info as! [String:Int] // このキャストは可...
print(pinfo) // [ "Height": 161, "Grade" : 2, "Level" ...
一般に Objective-C から渡される辞書には複数の型が含まれて...
ダウンキャストには as? 演算子を用いるか、要素毎に個別に対...
for (key, value) in info {
if let k = key as? String, v = value as? Int { // [St...
print(k + ": ", v)
}
}
または
for enry in info {
if case let (k as String, v as Int) = entry { // (Str...
print(k + ": ", v)
}
}
**NSValue と CoreGraphics の構造体 [#xc085fab]
CFLoat型はDoubleの場合とFloatの場合があるので、
Objective-Cでは自動型変換で大丈夫であっても、
Swiftではエラーとなることがある。
イニシャライザを使って明示的に型変換を行うとよい。
var xp: CFLoat = CGFloat(sin(th)) // sin() の返り値は...
var x2: Double = Double(xp * xp)
CoreGraphics で定義されている構造体
||データ型|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, CGR...
利用できる。
**NSData [#p2510913]
Objective-C の NSData に対応づけられた Swift の型はないの...
[Int8] 型、または [UInt8] 型でバイト列のデータをやりとり...
Objective-C から受け取ったNSDataからデータを読み出すには...
メソッド 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() と strideofVa...
strideof(Float80) // 16
strideofValue(["Cinderella":346]) // 8
**Core Foundation [#g928876d]
Foundation を import すると Core Foundation も import さ...
Core Foundation のオブジェクトを表す型名は
CFArrayRef , CFURLRef のように
参照型であることを示す Ref がついているが、Swiftでは
「Ref のある型名」も「Refのない型名」も両方使える。
Core Foundation の CFTypeRef 型は Swift の AnyObject 型と...
Core Foundation の型には toll-free (型変換なしにObjective...
なものがあるが、これは Swift でも利用できる。
|BGCOLOR(#0000ff): Core Foundation|BGCOLOR(#0000ff): Obje...
|CFArrayRef|NSArray|
|CFMutableArrayRef|NSMutableArray|
|CFDataAef|NSData|
|CFMutableDataAef|NSMutableData|
|CFDateAef|NSDate|
|CFDicitonaryAef|NSDictionary|
|CFMutableDictionaryAef|NSMutableDictionary|
|CFStringAef|NSString|
|CFMutableStringAef|NSMutableString|
|CFNumberAef|NSNumber|
|CFURLAef|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 { // 上記の共用体に対応する Sw...
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 { // 上記のビットフィールドに対応...
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, // 省略時は Localiza...
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(*co...
typealias Episode = (String, Int)
var buf:[Episode] = [ ("Parade",10), ("Baltazar", 5), (P...
qsort(&buf,buf.count,strideof(Episode)){
(x:UnsafePointer<Void>, y:UnsafePointer<Void>) -> Int3...
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), ("Parad...
**C言語のブロックオブジェクト [#ea3ffd2c]
Objective-C で定義されたブロックオブジェクトを Swift に渡...
Tはブロックオブジェクトの引数と返り値を表す型であり、たと...
@convention(block) T
int scale = 15;
[calc setScaleBlock:^(int n) {
return n * scale;
}];
このブロックオブジェクトは、swiftでは次のような型の変数に...
外側の括弧がないと型の解釈があいまいになることに注意(type...
var block: (@convention(block) (Int32) -> Int32) !
変数 block は Swift のクロージャであるかのように、引数を...
実行時には渡されるときにキャプチャした値(scale = 15)が使...
*Null許容性 (nullability) [#ibc37bcc]
Swiftのオプショナル型は変数がインスタンスを参照する場合と...
Objective-Cではあまり区別していなかった。
このようなObjective-Cの特性を扱うために導入された概念が N...
-NULL (または nil) でもよい場合 -- Null許容 (nullable)
-NULL (または nil) ではいけない場合 -- Null非許容 (nonnul...
Objective-C の Null 許容性の表現
- _Nullable --- Null許容。値が NULL や nil の場合がある。
- _Nonnull --- Null非許容。値が NULL や nil の場合はない。
- _Null_unspecified --- 指定なし。値が NULL や nil の場合...
クラス UIImage のクラスメソッド + imageWithData: は引数に...
+ (UIImage * _Nullable) imageWithData: (NSData * _Nonnul...
型修飾子ではなく、キーワード nullable, nonnull, null_rese...
+ (nullable UIImage *) imageWithData: (nonnull NSData *)...
オプショナル型と 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 *) ...
+ (nullable instancetype) initWithhero: (nonnull NSStrin...
@end
// Swift
public class HestiaParty : Party {
public var hero: String
public var helper: String?
public var knife: String!
public var supporter: String? // weakだと、インスタ...
public class func familia(famouse: String?) -> Self
public init?(hero: String)
}
終了行:
[[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 を代入でき、演算子 ==, != を用いてポイン...
|種類|C言語の型|Swiftの型|
|ポインタ|const T*|UnsafePointer<T>|
|~|T*|UnsafeMutablePointer<T>|
|~|void*|UnsafeMutablePointer<Void>|
|クラスTのインスタンス|const T*|UnsafePointer<T>|
|~|_strong T*|UnsafeMutablePointer<T>|
|~|T**|AutoreleasingUnsafeMutablePointer<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>,_:UnsafeMutabl...
import Darwin
var current = time(nil) // current は time_t 型になる
ポインタには「変数のポインタを渡す」場合と「配列の先頭要...
変数のポインタを渡す場合は、実引数として "&" をつけた変数...
var current: time_t = time_t() // 変数を用意して初期化
time(¤t) // 変数 current に値が...
import Darwin // Foundation でもよい
var current : time_t = time(nil) // 現在時刻を time_t ...
var tnow = tm() // 変数を用意して初期化
localtime_r(¤t, &tnow) // 変数 tnow に情報が...
print("\(tnow.tm_mon + 1)月\(tnow.tm_mday)日") // 本日...
***配列を用意して関数の結果を書き込む [#p36bd33d]
time_t型データから、日時を表す文字列を生成する ctime_r 関...
第1引数は time_t型へのポインタで、第2引数が文字列領域への...
C 言語の char 型は Swift では Int8 型なので
文字列領域へのポインタは UnsafeMutablePointer<Int...
func ctime_r(_: UnsafePointer<time_t>, _: UnsafeMutableP...
配列のポインタを関数に渡す場合、使い方は次の2通り。
-渡した配列の内容を関数で変更する場合。配列名に "&" を付...
-渡した配列の内容を関数で変更しない場合。配列名に "&" を...
import Darwin
var buf = (Int8)(count: 26, repeatedValue: 0) // 26個の0
var current: time_t = time(nil)
ctime_r(¤t,&buf) // 文字...
puts(buff) // 現在時刻が表示さ...
// puts(&buff) // &をつけても同じ結果が得られる
変数bufの値は Swift の String 型ではないので、表示するの...
C言語の puts を使うことはできる。
putsではポインタの内容を変更しないので、putsに与える実引...
つけなくてもどちらでも同じ動作となる。
var tt = [time(nil) ] // time_t 型の配列を作り、第1要...
ctime_r(tt,&buf) // &tt でも動作する
ポインタへの値の渡し方
||UnsafePointer<T> ~ 読み取り専用|UnsafeMutable&#...
|値が1つの変数 x:T|&x|&x|
|配列 a:[T]|aまたは&a|&a|
***C言語ポインタ引数に関するルール [#o68075c4]
Swift でC言語の fopen関数を使ってファイルをオープンするコ...
let fpin = fopen(path,"r") // 引数はSwiftの String 型
関数 fopen の Swift インタフェース
func fopen(_: UnsafePointer<Int8>, _: UnsafePointer<Int8...
String型と UnsafePointer<Int8> 型は互換ではない。
C言語のAPIを用いてSwiftを動作させるために、ポインタ引数に...
+関数の引数が UnsafePointer<T> 型で定義されているとき...
--nil
--UnsafePointer<T>
--UnsafeMutablePointer<T>
--AutoreleasingUnsafeMutablePointer<T>
--T型の引数に & を付けたもの (inoutが指定された引数と同様)
--T型の値。配列の先頭として渡され、配列は呼び出しが終わる...
&はつけてもつけなくても動作する。配列リテラルで渡すことも...
--String。ただし、Tは Int8 か UInt8 の場合。
文字列はバッファ内で UTF-8 に変換され、バッファは呼び出し...
+配列の引数が UnsafePointer<Void> 型で定義されている...
ポインタ UnsafePointer<T> について、上記1.で受取可能...
+関数の引数が UnsafeMutablePointer<T> 型で定義さ...
次の型の実引数を受け取ることができる。
--nil
--UnsafeMutablePointer<T>
--T型の書き込みが可能な変数に & をつけたもの。
--[T]型の書き込みが可能な変数に & をつけたもの。
+関数の引数が UnsafeMutablePointer<Void> 型で定義...
任意の型 T のポインタ UnsafeMutablePointer<T> に...
受取可能とした実引数を指定できる。
このルールにより Swift の String 型を C 言語の文字列のよ...
逆はできない。
引数として UnsafePointer<T> を受け取るC言語の関数に
UnsafeMutablePointer<T>
を渡しても動作する。しかし、
Swift では UnsafeMutablePointer<T>
と UnsafePointer<T> は異なる型なので、
型の変換を明示する必要がある。
let p: UnsafeMutablePointer<Int8> = /* 何かの値 */
let q: UnsafePointer<Int8>(p) // ポインタの型を変...
let z: UnsafePointer<Int8> = p // エラー。Swiftで...
unsafe pointer 間での相互変換は自由にできる。
つまり、T型とU型が無関係であっても
UnsafePointer<T>
を
UnsafePointer<U>
に、
UnsafeMutablePointer<T>
を
UnsafeMutablePointer<U>
に変換できる。どちらの型も2つのイニシャライザを持っている。
init<U>(_ from: UnsafeMutablePointer<U>)
init<U>(_ from: UnsafePointer<U>)
型パラメータ U には何の制限もないので、次のような変換も可...
let p: UnsafePointer<Int8> = /* char 型を読み出し可能な...
let q = UnsafeMutablePointer<Int32>(p) = /* 整数値を書き...
*** 渡されたポインタから値 を取り出す [#xfc6cdaa]
リエントラント(再入可能)でスレッドセーフな関数は名前の末...
元々 Unixで用意されていた関数は localtime, ctime でありリ...
これらを Swift から利用してみる。
func localtime(_: UnsafePointer<time_t>) -> UnsafeMutabl...
func ctime(_ UnsafePointer<time_t>) -> UnsafeMutablePoin...
3種類の unsafe pointer は Swift では構造体として定義され...
ポインタの指す内容にアクセスするプロパティ memory と、
参照しているメモリを先頭から配列のように参照できる添字付...
// UnsafeMutablePointer<T> 型の場合
var memory: T { get nonmutating set }
subscript (i: Int) -> T { get nonmutating set }
UnsafeMutablePointer<T> は C 言語の (T*) 型に相当...
これらの型をもつ変数 p の値にアクセスするには、C言語では ...
Swift では p.memory と記述する。
ポインタの位置からデータ n 個分先のデータにアクセスするには
C言語でもSwiftでも p[n] と記述する。
// unsafe pointer に直接アクセスする例
import Darwin
var current = time(nil)
let jnow: tm = localtime(¤t).memory // 構造体を...
print("\(jnow.tm_mon + 1)月\(jnow.tm_mday)日")
let p = ctime(¤t) // pは UnsafeMutablePointer...
for i in 0..<25 { // 添字を使って文字にアクセ...
putchar(Int32(p[i])) // putcharの引数はint型(Int...
} // 最後の文字は改行文字
var ptr = p // ポインタを進めながら文字...
for i in 0..<25 {
putchar(Int32(ptr.memory)) // ポインタの指すデータを表...
ptr = ptr.successor() // ポインタを1つ進める
}
Swift ではポインタを直接変数に代入することはできないので...
コピーが代入される。
***ポインタから文字列への変換 [#b1fbe9a0]
String型のタイプメソッドを使う。
static func fromCString(_: UnsafePointer<CChar>) -> Stri...
let p = ctime(¤t) // pはUnsafeMutablePointer<...
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<UnsafeMutabl...
var i = 0
for elm in Process.arguments {
print("\(i++): \(elm)")
}
***UnsafeBufferPointer<T>を利用する [#ef1e93f0]
unsafe pointer には添字でアクセスする方法以外に、
プロトコル CollectionType に適合している
構造体 UnsafeBufferPointer<T>
を利用する方法もある。
uptr: UnsafePointer<Int> = /* 略 */
let array = UnsafeBufferPointer<Int>(start: uptr, count:...
*** T**型の引数の扱い [#a280dc53]
-TがC言語の単純型の場合~
C言語の T** は Swift では
UnsafeMutablePointer<UnsafeMutablePointer...
となる。
-TがObjective-Cのクラスの場合~
Objective-Cでは、メソッドに渡される T** 型は
「クラス T のインスタンスを格納するローカル変数へのポイン...
または「nil」であり、グローバル変数や配列であってはならな...
Swift側からObjective-C側にポインタを渡すとき(ローカル変数...
T**型を
AutoreleasingUnsafeMutablePointer<T>
として扱う。すなわち、渡されたポインタがnilでなければ、ク...
一時的に作成されて利用され、関数の終了時にポインタが指す...
*対応付けられたデータ型 [#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 すれば St...
NSString型に変換して機能を利用する必要はない。
Swift の String 型と Objective-C の NSMutableString ...
互いに自由に変換はできない。
ただし、NSMutableString型は NSString型のサブクラスな...
NSString はクラスクラスタなので、実際の型が NSString であ...
** 配列と集合 [#g176deb5]
Swift の Array 型と Objective-C の NSArray 型は対応付けら...
NSArray 型で型パラメータを指定しない配列オブジェクトは
Swift の [ AnyObject ] という型に対応付けられる。
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 から渡された [ AnyObject ]型の配列の要素...
たとえば文字列だけを取り出したい場合は次のようにクロージ...
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 : AnyObject ]
という型となる。
let info: NSDictionary = [ "Height" : 161.0, "Grade" : 2...
let pinfo = info as! [String:Int] // このキャストは可...
print(pinfo) // [ "Height": 161, "Grade" : 2, "Level" ...
一般に Objective-C から渡される辞書には複数の型が含まれて...
ダウンキャストには as? 演算子を用いるか、要素毎に個別に対...
for (key, value) in info {
if let k = key as? String, v = value as? Int { // [St...
print(k + ": ", v)
}
}
または
for enry in info {
if case let (k as String, v as Int) = entry { // (Str...
print(k + ": ", v)
}
}
**NSValue と CoreGraphics の構造体 [#xc085fab]
CFLoat型はDoubleの場合とFloatの場合があるので、
Objective-Cでは自動型変換で大丈夫であっても、
Swiftではエラーとなることがある。
イニシャライザを使って明示的に型変換を行うとよい。
var xp: CFLoat = CGFloat(sin(th)) // sin() の返り値は...
var x2: Double = Double(xp * xp)
CoreGraphics で定義されている構造体
||データ型|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, CGR...
利用できる。
**NSData [#p2510913]
Objective-C の NSData に対応づけられた Swift の型はないの...
[Int8] 型、または [UInt8] 型でバイト列のデータをやりとり...
Objective-C から受け取ったNSDataからデータを読み出すには...
メソッド 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() と strideofVa...
strideof(Float80) // 16
strideofValue(["Cinderella":346]) // 8
**Core Foundation [#g928876d]
Foundation を import すると Core Foundation も import さ...
Core Foundation のオブジェクトを表す型名は
CFArrayRef , CFURLRef のように
参照型であることを示す Ref がついているが、Swiftでは
「Ref のある型名」も「Refのない型名」も両方使える。
Core Foundation の CFTypeRef 型は Swift の AnyObject 型と...
Core Foundation の型には toll-free (型変換なしにObjective...
なものがあるが、これは Swift でも利用できる。
|BGCOLOR(#0000ff): Core Foundation|BGCOLOR(#0000ff): Obje...
|CFArrayRef|NSArray|
|CFMutableArrayRef|NSMutableArray|
|CFDataAef|NSData|
|CFMutableDataAef|NSMutableData|
|CFDateAef|NSDate|
|CFDicitonaryAef|NSDictionary|
|CFMutableDictionaryAef|NSMutableDictionary|
|CFStringAef|NSString|
|CFMutableStringAef|NSMutableString|
|CFNumberAef|NSNumber|
|CFURLAef|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 { // 上記の共用体に対応する Sw...
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 { // 上記のビットフィールドに対応...
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, // 省略時は Localiza...
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(*co...
typealias Episode = (String, Int)
var buf:[Episode] = [ ("Parade",10), ("Baltazar", 5), (P...
qsort(&buf,buf.count,strideof(Episode)){
(x:UnsafePointer<Void>, y:UnsafePointer<Void>) -> Int3...
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), ("Parad...
**C言語のブロックオブジェクト [#ea3ffd2c]
Objective-C で定義されたブロックオブジェクトを Swift に渡...
Tはブロックオブジェクトの引数と返り値を表す型であり、たと...
@convention(block) T
int scale = 15;
[calc setScaleBlock:^(int n) {
return n * scale;
}];
このブロックオブジェクトは、swiftでは次のような型の変数に...
外側の括弧がないと型の解釈があいまいになることに注意(type...
var block: (@convention(block) (Int32) -> Int32) !
変数 block は Swift のクロージャであるかのように、引数を...
実行時には渡されるときにキャプチャした値(scale = 15)が使...
*Null許容性 (nullability) [#ibc37bcc]
Swiftのオプショナル型は変数がインスタンスを参照する場合と...
Objective-Cではあまり区別していなかった。
このようなObjective-Cの特性を扱うために導入された概念が N...
-NULL (または nil) でもよい場合 -- Null許容 (nullable)
-NULL (または nil) ではいけない場合 -- Null非許容 (nonnul...
Objective-C の Null 許容性の表現
- _Nullable --- Null許容。値が NULL や nil の場合がある。
- _Nonnull --- Null非許容。値が NULL や nil の場合はない。
- _Null_unspecified --- 指定なし。値が NULL や nil の場合...
クラス UIImage のクラスメソッド + imageWithData: は引数に...
+ (UIImage * _Nullable) imageWithData: (NSData * _Nonnul...
型修飾子ではなく、キーワード nullable, nonnull, null_rese...
+ (nullable UIImage *) imageWithData: (nonnull NSData *)...
オプショナル型と 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 *) ...
+ (nullable instancetype) initWithhero: (nonnull NSStrin...
@end
// Swift
public class HestiaParty : Party {
public var hero: String
public var helper: String?
public var knife: String!
public var supporter: String? // weakだと、インスタ...
public class func familia(famouse: String?) -> Self
public init?(hero: String)
}
ページ名: