Swift逆引きハンドブック Swift 2.2対応 ■Section 006, P.58 ★デバッグに便利なリテラル Swift 2.2では以下のように変更されました。 「__FILE__」 -> 「#file」 「__LINE__」 -> 「#line」 「__COLUMN__」 -> 「#column」 「__FUNCTION__」-> 「#function」 ■Section 011, P.71 ○インクリメント・デクリメントについて Swift 2.2で、インクリメントとデクリメントは非推奨となりました。 Swift 2.2以降では、以下のように、「+=」や「-=」を使うようにしてください。 i += 1 i -= 1 なお、Xcodeのコード修正機能では前置インクリメント/デクリメント、後置インクリメント/デクリメントのどちらも、「+=」や「-=」に置き換えられます。本文で解説している通り、前置か後置かによって値が更新されるタイミングが異なるため、単純に置き換えると正しく動かなくなる場合があります。インクリメントやデクリメントを使っているコードを、Swift 2.2対応に更新するときには、注意してください。 ■Section 015, P.98 ○「for」を使ったループについて 「初期化」「ループ条件」「ループ変数の更新」を指定する形式の「for」(Cスタイルの「for」)は非推奨となりました。 Swift 2.2以降では、P.102「★範囲を指定してループさせる」で解説している、範囲指定を使ったループに置き換えることが推奨されています。 例えば、「for var i = 0; i < 10; i++」であれば、以下のように置き換えます。 ==== for i in 0 ..< 10 { print("i = \(i)") } ==== ■Section 015, P.100 ★無限ループを行う Cスタイルの「for」が非推奨となったので、無限ループは、次のように「while」を使って記述します。 また、インクリメントも非推奨になったので、コードを以下のように変更します。 ==== // 変数を定義する var i = 0 // 無限ループ // (ループ条件を指定していない) while true { // カウントを増やしつつ、文字列を出力 print("\(i):LOOP") i += 1 } ==== ■Section 016, P.104 ○「while」を使ったループについて インクリメントが非推奨となったので、以下のように変更します。 ==== // 合計を入れる変数 var sum = 0 // カウンタ var i = 0 // ループさせる // 変数「sum」が30未満の間、ループする while sum < 30 { // 合計を計算 sum += i // 現在の値を出力する print("\(i):\(sum)") // カウンタを更新する i += 1 } ==== P.105 ★「while」を使ったループの中断とスキップ インクリメントが非推奨となったので、以下のように変更します。 変更前のコードは後置インクリメントだったので、先に値を更新するコードにすると、値をチェックするタイミングが変わるため、チェックする条件式を次のように変更する必要があります。 ==== // 変数を定義する var i = 0 // 変数「i」が10未満の間ループする while i < 10 { // 文字列を出力する print("i = (\(i))") // 変数「i」を更新し、4未満ならば残りの処理をスキップする i += 1 if i < 4 { continue; } // 文字列を出力する print("break") // ループを中断する break } ==== ■Section 017, P.107 ○ループや「switch」の入れ子について インクリメントが非推奨となったので、以下のようにコードを変更します。 ==== // 変数を定義する var i = 0, j = 0 while i < 10 { while j < 10 { // ループを中断する break // 中断されたので、この行は実行されない j += 1 } // この行は実行される i += 1 } // 変数「i」と「j」の値を出力する print("i=\(i), j=\(j)") ==== P.108, 「switch」やループにラベルを付ける インクリメントが非推奨となったので、以下のようにコードを変更します。 ==== // 変数を定義する var i = 0, j = 0 outer: while i < 10 { iner: while j < 10 { // 外側のループを中断する break outer // 中断されたので、この行は実行されない j += 1 } // この行は実行される i += 1 } // 変数「i」と「j」の値を出力する print("i=\(i), j=\(j)") ==== ■Section 019, P.125 ○可変引数を定義する インクリメントが非推奨となったので、以下のようにコードを変更します。 ==== // 関数を定義する func createNameList(names: String...) -> String { var i = 0 // 渡された文字列を1つずつ取り出す var str:String = "" for name in names { // 文字列を結合する str += "\(i): \(name)\n" i += 1 } // 作った文字列を返す return str } // 関数を呼び出す var str = createNameList() print("* EMPTY *") print(str) // 3件指定して呼び出す str = createNameList("Apple", "Car", "Tree") print("* 3 items *") print(str) ==== ■Section 020, P.127 ○Swiftでの関数オブジェクトについて インクリメントが非推奨となったので、以下のようにコードを変更します。 ==== // 関数「printArray」が呼び出す関数 // インデックス番号も出力する func printItemWithIndex(index: Int, item: Any) { // 項目を一つ出力する print(" [\(index)] = '\(item)'") } // 関数「printArray」が呼び出す関数 // インデックス番号を出力しない func printItem(index: Int, item: Any) { // 項目を一つ出力する print(" \(item)") } // コールバック関数を使って、項目を出力する関数を定義する func printArray(itemArray: [Any], itemWriter: (Int, Any) -> Void) { // アイテム数を出力する print("item count = \(itemArray.count)") // 各アイテムを関数オブジェクトを使って出力する var index: Int = 0 for item in itemArray { // 関数オブジェクトを使って、項目を出力する itemWriter(index, item) index += 1 } } // 出力する配列を定義する let array: [Any] = [1, "A", "B", 5, 0.2] // インデックス番号を出力しない関数オブジェクトを指定して出力する printArray(array, itemWriter: printItem) // インデックス番号を出力する関数オブジェクトを指定して出力する printArray(array, itemWriter: printItemWithIndex) ==== ■Section 027, P.154 COLUMN 「Raw Value」から変換できないことについて Cスタイルのforループが非推奨となったため、以下のようにコードを変更します。 ==== // 列挙を定義する enum SignalColor: Int { case Red, Yellow, Blue } // 値を変化させながら列挙に変換できたかをチェックする for i in 0 ..< 4 { var colorName: String? // 変換と同時に「nil」チェックを行う if let color = SignalColor(rawValue: i) { // 変換できたとき(「nil」以外) // 列挙の値によって分岐 switch color { case .Red: colorName = "Red" case .Yellow: colorName = "Yellow" case .Blue: colorName = "Blue" } } else { // 変換できなかったとき(「nil」になったとき) colorName = "---" } // 結果を出力 print("fromRaw(\(i)) = \(colorName!)") } ==== ■Section 046, P.239 COLUMN アソシエーテッドタイプと組み合わせ Swift 2.2以降では、アソシエーテッドタイプの定義は「typealias」ではなく、「associatedtype」を使うように変更されました。 コードを以下のように変更します。 ==== // プロトコル「MyValue」を定義する protocol MyValue { associatedtype ValueType var value: ValueType { get } } // プロコトル「MyValue」に準拠する構造体を定義する struct IntValue : MyValue { // 「ValueType」を「Int」にする typealias ValueType = Int // プロパティを定義する var value: ValueType = 0 } struct DoubleValue : MyValue { // 「ValueType」を「Double」にする typealias ValueType = Double // プロパティを定義する var value: ValueType = 0.0 } // プロトコル「MyValue」に準拠した構造体の値が等しいかをチェックする関数 func isEqualMyValue(v1: T1, _ v2: T2) -> Bool { return v1.value == v2.value } // インスタンスを確保する var v1: IntValue = IntValue() var v2: IntValue = IntValue() var v3: DoubleValue = DoubleValue() // 関数「isEqualMyValue」を呼び出す isEqualMyValue(v1, v2) // 次の行は、アソシエーテッドタイプが異なるため、コンパイルエラーになる isEqualMyValue(v1, v3) ==== ■Section 047, P.243 - P.244 「try」の後ろの「!」が抜けています。正しいコードは以下の通りです。 ==== import Foundation // エラーを定義する enum MyError: ErrorType { case OutOfBounds } // 配列の指定した範囲内の合計を計算する関数 func sum(values: [Int], index: Int, length: Int) throws -> Int { // 指定された範囲が、配列の有効範囲内かどうかを判定する if (index < 0 || (index + length) > values.count) { // 範囲外 throw MyError.OutOfBounds } var ret = 0 for i in 0 ..< length { ret += values[i + index] } return ret } // 配列を定義する let values = [1, 2, 3, 4, 5] // 正常な範囲を指定した場合 var ret = try! sum(values, index: 1, length: 3) print(ret) // 無効な範囲を指定した場合 ret = try! sum(values, index: 10, length: 3) print(ret) ==== ■Section 053, P.261 ONEPOINT インスタンスがメソッドを実装しているか調べるには「respondsToSelector」メソッドを使う Swift 2.2以降では、セレクタの構文が以下のように変わりました。 #selector(タイプ.メソッド) #selector(タイプ.メソッド(引数)) 引数はObjective-Cと同じで「:」で連結して記述します。また、外部引数名を持たない引数については、「_」を記述します。 メソッドの定義が無い場合には、従来通り文字列表現を使用しますが、次のように「Selector」を使った構文にします。 Selector("セレクタの文字列表現") サンプルコードは以下のように変更します。 ==== // 「NSObject」クラスを使うので「Foundation」をインポートする import Foundation // 「NSObject」クラスのサブクラスとして定義する class Point2D : NSObject { // プロパティを定義する var x = 0 var y = 0 // 引数が無いメソッドを定義する func reset() { self.x = 0 self.y = 0 } // 引数があるメソッドを定義する func moveToX(toX: Int, toY: Int) { self.x = toX self.y = toY } } // インスタンスを確保する var pt = Point2D() // メソッド「reset」を実装しているか調べる if pt.respondsToSelector(#selector(Point2D.reset)) { print("pt responds to 'reset'") } else { print("pt doesn't respond to 'reset'") } // メソッド「moveToX」を実装しているか調べる // 引数のラベルも指定する必要がある if pt.respondsToSelector(#selector(Point2D.moveToX(_:toY:))) { print("pt responds to 'moveToX:toY:'") } else { print("pt doesn't respond to 'moveToX'") } // メソッド「moveToX」を実装しているか調べる // ラベルを指定しないと別のメソッドとして扱われてしまうので認識できない if pt.respondsToSelector(Selector("moveToX")) { print("pt responds to 'moveToX'") } else { print("pt doesn't respond to 'moveToX'") } ==== ■Section 053, P.262 COLUMN プロパティを持っているか調べるには セレクタの構文が変わったため、次のようにコードを変更します。 ==== // 「NSObject」クラスを使うので「Foundation」をインポートする import Foundation // 「NSObject」クラスのサブクラスとして定義する class Point3D : NSObject { // プロパティを定義する var locX = 0 // 読み込み専用プロパティにする var locY: Int { get { return 0 } } } // プロパティの実装状況を返す関数 func implementStatus(obj: AnyObject, getSel: Selector, setSel: Selector) -> String { if obj.respondsToSelector(getSel) && obj.respondsToSelector(setSel) { return "Read Write" } else if obj.respondsToSelector(getSel) { return "Read Only" } else { return "Not Implemented" } } // インスタンスを確保する var pt = Point3D() // プロパティ「locX」「locY」「locZ」について取得用メソッドと // 設定用メソッドが定義されているかを調べる // プロパティ「locX」について調べる var status = implementStatus(pt, getSel: Selector("locX"), setSel: Selector("setLocX:")) print("pt.locX : " + status) // プロパティ「locY」について調べる status = implementStatus(pt, getSel: Selector("locY"), setSel: Selector("setLocY:")) print("pt.locY : " + status) // プロパティ「locZ」について調べる status = implementStatus(pt, getSel: Selector("locZ"), setSel: Selector("setLocZ:")) print("pt.locZ : " + status) ==== ■Section 056, P.269 セレクタの構文が変わったので、以下のようにコードを変更します。 ==== // 「Foundation」の機能を使う import Foundation class MyClass : NSObject { // インスタンスメソッドを定義する func calc(x: Int, y: Int, z: Int) -> Int { return (x + y + z) } // タイプメソッドを定義する class func typeMethod() { } } // メソッド(セレクタ)を文字列にする var method1 = NSStringFromSelector(#selector(MyClass.calc(_:y:z:))) var method2 = NSStringFromSelector(#selector(MyClass.typeMethod)) print(method1) print(method2) ==== ■Section 079, P.328 「Range」構造体の「init(start:end:)」というイニシャライザは非推奨となりました。 Swift 2.2以降では、「..<」(範囲演算子)を使って記述します。 ==== import Foundation // 元の文字列を定義する let srcStr = "Swift逆引きハンドブック" // インデックス番号5から3文字抜き出す let start = srcStr.startIndex.advancedBy(5) let end = srcStr.startIndex.advancedBy(8) let str = srcStr.substringWithRange(start ..< end) // 抜き出した文字列を出力する print(str) ==== ■Section 082, P.339 COLUMN 前後の文字列を検索するには 「Range」構造体の「init(start:end:)」イニシャライザメソッドが非推奨となったため、以下のようにコードを変更します。 ==== import Foundation // 文字列を定義する let text = "Swift Swift Swift" let text2: NSString = "Swift Swift Swift" // 最初は全体を検索範囲にする var range = Range(text.startIndex ..< text.endIndex) // 「break」するまでループする while true { // 変数「range」の範囲を検索する var found = text.rangeOfString("Swift", options: .BackwardsSearch, range: range) // 見つからなかったらループ中断 if found == nil { break } // 見つかった位置を出力 print(found) // 検索範囲の終了位置を、見つかった位置の先頭に設定する range.endIndex = found!.startIndex } // 「NSString」クラスの場合 // 最初は全体を検索範囲にする var range2 = NSMakeRange(0, text2.length) // 「break」するまでループする while true { // 変数「range2」の範囲を検索する var found = text2.rangeOfString("Swift", options: .BackwardsSearch, range: range2) // 見つからなかったらループ中断 if found.location == NSNotFound { break } // 見つかった位置を出力 print(found) // 検索範囲の終了位置を、見つかった位置の先頭に設定する range2.length = found.location } ==== ■Section 082, P.342 COLUMN 大文字・小文字を無視するには 「Range」構造体の「init(start:end:)」イニシャライザメソッドが非推奨となったため、以下のようにコードを変更します。 ==== import Foundation // 文字列を定義する let text = "swift SWIFT Swift" let text2: NSString = "swift SWIFT Swift" // 最初は全体を検索範囲にする var range = Range(text.startIndex ..< text.endIndex) // 「break」するまでループする while true { // 変数「range」の範囲を検索する // 大文字小文字を無視するので「CaseInsensitiveSearch」を指定する var found = text.rangeOfString("Swift", options: .CaseInsensitiveSearch, range: range) // 見つからなかったらループ中断 if found == nil { break } // 見つかった位置を出力 print(found) // 検索範囲の開始位置を更新する range.startIndex = found!.endIndex if range.startIndex != range.endIndex { // 一つ後ろにずらす range.startIndex = range.startIndex.successor() } else { // 末尾に到達 break } } // 「NSString」クラスの場合 // 最初は全体を検索範囲にする var range2 = NSMakeRange(0, text2.length) // 「break」するまでループする while true { // 変数「range2」の範囲を検索する // 大文字小文字を無視するので「CaseInsensitiveSearch」を指定する var found = text2.rangeOfString("Swift", options: .CaseInsensitiveSearch, range: range2) // 見つからなかったらループ中断 if found.location == NSNotFound { break } // 見つかった位置を出力 print(found) // 検索範囲の開始位置を更新する range2.location = found.location + found.length range2.length = text2.length - range2.location } ==== ■Section 084, P.350 COLUMN 文字列の一部を比較するには 「Range」構造体の「init(start:end:)」イニシャライザメソッドが非推奨となったため、以下のようにコードを変更します。 ==== import Foundation // 「NSComparisonResult」を文字列で返す関数 func strOfResult(result: NSComparisonResult) -> String { switch result { case .OrderedAscending: return "OrderedAscending" case .OrderedDescending: return "OrderedDescending" case .OrderedSame: return "OrderedSame" } } // 比較する文字列を定義する var str = "1. Swift" // インデックス番号3から5文字の範囲を比較する let start = str.startIndex.advancedBy(3) let end = str.startIndex.advancedBy(8) var range = Range(start ..< end) // 比較する var result = str.compare("Swift", options: NSStringCompareOptions(), range: range) // 結果を出力する print(strOfResult(result)) ==== ■Section 102, P.394 COLUMN 指定した範囲の要素を削除するには 「Range」構造体の「init(start:end:)」イニシャライザメソッドが非推奨となったため、以下のようにコードを変更します。 ==== import Foundation // 配列を定義する var array = [0, 1, 2, 3, 4] // コンソールに出力する print(array) // インデックス番号1から3までの範囲を削除する array.removeRange(1 ..< 4) // コンソールに出力する print(array) ==== ■Section 103, P.397 「Range」構造体の「init(start:end:)」イニシャライザメソッドが非推奨となったため、以下のようにコードを変更します。 ==== import Foundation // 配列を定義する var array = [1, 2, 3, 4, 5] // コンソールに出力する print(array) // 先頭と2番目の要素を置き換える array.replaceRange(0 ..< 2, with: [10, 11]) // コンソールに出力する print(array) ==== ■Section 107, P.405 COLUMN 部分検索するには Cスタイル「for」文が非推奨となったので、以下のように、「while」に置き換えます。 ==== import Foundation // 配列を定義する var array: NSArray = ["Car", "Book", "Tree", "Book", "Book"] // コンソールに出力する print(array) // 最初は全体を検索する var range = NSMakeRange(0, array.count) // 繰り返す while true { // 「Book」を検索する var idx = array.indexOfObject("Book", inRange: range) if idx == NSNotFound { // 見つからなかったのでループ終了 break } // インデックス番号をコンソールに出力 print(idx) // 検索する範囲を見つかったインデックス番号の次から末尾までに変更 range = NSMakeRange(idx + 1, array.count - (idx + 1)) } ==== ■Section 145, P.502 COLUMN 追加回数が多いときは別の方法を検討する インクリメントが非推奨になったので、以下のようにコードを変更します。 ==== import Foundation // 「appendBytes」メソッドを繰り返して、データを構築する // totalLengthにデータの合計サイズ、pieceLengthに1回の追加で使用する // バッファサイズを指定する。 // 作業に必要だった時間と「appendBytes」メソッドの呼び出し回数が返る func buildData(totalLength: Int, pieceLength: Int) -> (Double, Int) { // バッファを確保する let buf = malloc(pieceLength) guard buf != nil else { return (0, 0) } let bufPtr = unsafeBitCast(buf, UnsafeMutablePointer.self) // 変更可能なデータを確保する let data = NSMutableData() // ここから時間を計測する let startDate = NSDate() var dataLen: Int = 0 var value = 0 var count = 0 while dataLen < totalLength { // 追加する情報をバッファに設定する var bufLen = pieceLength if bufLen > (totalLength - dataLen) { bufLen = totalLength - dataLen } for i in 0 ..< bufLen { bufPtr[i] = UInt8(value) value += 1 if value > 255 { value = 0 } } data.appendBytes(bufPtr, length: bufLen) count += 1 dataLen += bufLen } // 経過時間を計算する let dt = NSDate().timeIntervalSinceDate(startDate) // バッファを解放する free(buf) return (dt, count) } // 一括でデータを確保して、バッファに直接アクセスして設定する func buildDataOnce(totalLength: Int) -> Double { // データを確保する let data = NSMutableData(length: totalLength) // ここから時間を計測する let startDate = NSDate() // バッファを取得する let p = unsafeBitCast(data!.mutableBytes, UnsafeMutablePointer.self) var value = 0 for i in 0 ..< totalLength { p[i] = UInt8(value) value++ if value > 255 { value = 0 } } // 経過時間を計算する let dt = NSDate().timeIntervalSinceDate(startDate) return dt } // データのサイズを定義する let dataLen = 10000000 // 一括確保の結果を取得する var dt = buildDataOnce(dataLen) var str = String(format: "Allocate at Once, Time = %.7f sec", dt) print(str) // 「appendBytes」メソッドで追加するバイト長を定義する let pieceLengthArray = [10000, 1000, 100, 10, 1] // 各バイト長で呼び出して、結果を出力する for pieceLen in pieceLengthArray { var ret = buildData(dataLen, pieceLength: pieceLen) var str = String(format: "BufLen = %d, NumOfCalled = %d, Time = %.7f sec", pieceLen, ret.1, ret.0) print(str) } ==== ■Section 146, P.508 COLUMN データの一部分を削除するには Swift 2.2以降では、「UnsafePointer」構造体の「init()」イニシャライザメソッドは非推奨になりました。 Swift 2.2以降では、「nil」を使用し、以下のようにコードを変更します。 ==== import Foundation // 変更可能なデータを作る var array: [UInt8] = [1, 2, 3, 3, 3, 4] var data = NSMutableData(bytes: &array, length: 6) // コンソールに出力する print(data) // インデックス番号3から2バイト削除する var range = NSMakeRange(3, 2) data.replaceBytesInRange(range, withBytes: nil, length: 0) // コンソールに出力する print(data) ==== ■Section 234, P.734, Observer.swift Swift 2.2以降では、セレクタは「#selector」を使用するので、以下のようにコードを変更します。 ==== import Foundation class Observer: NSObject { // インスタンス解放時の処理 deinit { // ノーティフィケーションの通知受け取り解除 let center = NSNotificationCenter.defaultCenter() center.removeObserver(self) } // ノーティフィケーションの受信準備 func setupObserver() { // ノーティフィケーションを受信する let center = NSNotificationCenter.defaultCenter() center.addObserver(self, selector: #selector(Observer.testNotification(_:)), name: NotifierTestNotification, object: nil) } // ノーティフィケーション受信時の処理 func testNotification(notification: NSNotification) { // コンソールにメッセージを表示する print("Received Notification") } } ==== ■Section 234, P.737 Observer.swift COLUMN 追加情報を取得するには Swift 2.2以降では、セレクタは「#selector」を使用するので、以下のようにコードを変更します。 ==== import Foundation class Observer: NSObject { // インスタンス解放時の処理 deinit { // ノーティフィケーションの通知受け取り解除 let center = NSNotificationCenter.defaultCenter() center.removeObserver(self) } // ノーティフィケーションの受信準備 func setupObserver() { // ノーティフィケーションを受信する let center = NSNotificationCenter.defaultCenter() center.addObserver(self, selector: #selector(Observer.testNotification(_:)), name: NotifierTestNotification, object: nil) } // ノーティフィケーション受信時の処理 func testNotification(notification: NSNotification) { // 追加情報を取得する if let userInfo = notification.userInfo { // 付与されたメッセージを取得する if let msg = userInfo[NotifierMessage] as? String { // コンソールにメッセージを表示する print(msg) } } } } ==== ■Section 234, P.739 Observer.swift COLUMN ノーティフィケーションを投げたオブジェクトでフィルタリングするには Swift 2.2以降では、セレクタは「#selector」を使用するので、以下のようにコードを変更します。 ==== import Foundation class Observer: NSObject { // インスタンス解放時の処理 deinit { // ノーティフィケーションの通知受け取り解除 let center = NSNotificationCenter.defaultCenter() center.removeObserver(self) } // ノーティフィケーションの受信準備 func setupObserver(notifier: AnyObject) { // ノーティフィケーションを受信する let center = NSNotificationCenter.defaultCenter() center.addObserver(self, selector: #selector(Observer.testNotification(_:)), name: NotifierTestNotification, object: notifier) } // ノーティフィケーション受信時の処理 func testNotification(notification: NSNotification) { // 追加情報を取得する if let userInfo = notification.userInfo { // 付与されたメッセージを取得する if let msg = userInfo[NotifierMessage] as? String { // コンソールにメッセージを表示する print(msg) } } } } ==== ■Section 237, P.747, CountDown.swift Swift 2.2以降では、セレクタは「#selector」を使用し、デクリメントは非推奨になったので、以下のようにコードを変更します。 ==== import Foundation // カウントダウンを行うクラス class CountDown: NSObject { // カウンター var counter: Int = 5 // タイマー var timer: NSTimer? // カウントダウンを開始するメソッド func startCountDown() { // タイマーを作成する // ここでは1秒ごとに呼び出すタイマーを作っている self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(CountDown.countDownByTimer(_:)), userInfo: nil, repeats: true) // 開始時のカウンターを出力する print(self.counter) } // タイマーで実行するメソッド func countDownByTimer(timer: NSTimer) { // カウンターをデクリメント self.counter -= 1 // カウンターを出力する print(self.counter) // 0になったらタイマーを停止する if self.counter == 0 { timer.invalidate() self.timer = nil } } } ==== ■Section 237, P.749, Delay.swift COLUMN 作成時に指定した追加情報を取得するには Swift 2.2以降では、セレクタは「#selector」を使用するので、以下のようにコードを変更します。 ==== import Foundation // タイマーで実行する処理を実装したクラス class Delay: NSObject { // タイマーの配列 var timers: [NSTimer] = [] // タイマーを作成する func startTimers() { // 1秒ごとに実行するタイマーを作る var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(Delay.timerProc(_:)), userInfo: "Timer A", repeats: true) timers.append(timer) // 0.4秒ごとに実行するタイマーを作る timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(Delay.timerProc(_:)), userInfo: "Timer B", repeats: true) timers.append(timer) // 1.2秒ごとに実行するタイマーを作る timer = NSTimer.scheduledTimerWithTimeInterval(1.2, target: self, selector: #selector(Delay.timerProc(_:)), userInfo: "Timer C", repeats: true) timers.append(timer) } // タイマーで実行するメソッド func timerProc(timer: NSTimer) { // 追加情報を取得する。このサンプルでは文字列として取得する if let str = timer.userInfo as? String { // コンソールに出力する print(str) } } } ==== ■Section 237, P.752, Delay.swift COLUMN 遅延処理の実装にタイマーを使う Swift 2.2以降では、セレクタは「#selector」を使用するので、以下のようにコードを変更します。 ==== import Foundation // タイマーで実行する処理を実装したクラス class Delay: NSObject { // タイマー var timer: NSTimer? // 終了フラグ var exit: Bool = false // タイマーの作成または遅延 func delayOperation() { // タイマーが作成済みか? if self.timer != nil { // 作成済みなので、実行時間を1秒後にセットする self.timer!.fireDate = NSDate(timeIntervalSinceNow: 1) } else { // タイマーを作成する self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(Delay.timerProc(_:)), userInfo: nil, repeats: false) } } // タイマーで実行するメソッド func timerProc(timer: NSTimer) { // コンソールにメッセージを出力する print("The timer is fired") // 終了フラグをセット self.exit = true } } ==== ■Section 238, P.755, Delay.swift Swift 2.2以降では、セレクタは「#selector」を使用するので、以下のようにコードを変更します。 ==== import Foundation // タイマーで実行する処理を実装したクラス class Delay: NSObject { // タイマー var timer: NSTimer? // タイマーの作成 func startTimer() { self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: #selector(Delay.timerProc(_:)), userInfo: nil, repeats: true) } // タイマーで実行するメソッド func timerProc(timer: NSTimer) { // コンソールに文字列を出力 print(".") } } ====