全体的に

Swift 3.0に対応するには、全体的に次のような変更を行う必要があり、このドキュメントでの訂正情報は主にこれらに従ったものになっています。

  • 「NS」から始まっているクラス、定数などの置き換え

  • 関数やメソッドの第1引数の外部引数名が、デフォルトで追加されるようになったことによる、コード変更

  • Enumのメンバーは小文字で始めるやメソッド名の変更など、「Swift API Design Guidelines」に沿った名称の変更

「Swift API Design Guidelines」に沿った名称変更は、サンプルコードで定義している定数については行っておりません。このドキュメントではビルド出来ないエラーに対する訂正情報を主目的としております。今後、新規で記述するコードについては「Swift API Design Guidelines」に従った名称にするのが望ましいでしょう。

「Swift API Design Guidelines」については、次のリンクを参照してください。

また、SwiftはSwift 2.2でも様々な変更が加えられています。Swift 2.2での変更に対応するための訂正情報については、次のリンクを参照してください。

Foundationのクラスについて

本書が書かれた時点では、「NSData」クラスに対応する、Swiftのネイティブの型はありませんでしたが、Swift 3.0では「Data」という新しい構造体が追加されています。他にも追加されたネイティブの型があります。

本ドキュメントでは、一部の型は置き換えておりますが、基本的にはこれらの型への置き換えは行っておりません。また、これらの型を引数に取るように変更されているメソッドについては、キャストを行っています。既存のコードについては、このドキュメントで書いているような方法で対応することが可能です。しかし、新規で記述するコードの場合は、積極的にSwiftネイティブの型を使う方が望ましいと思います。

従来からあるクラスでも、メソッドの戻り値などは新しいSwiftネイティブの型が戻されるようになっているものがあり、いつの間にか新しい型を使っているということもあります。

P.48, 「print」関数以外のログ出力関数について

「stringByExpandingTildInPath」メソッドが「expandingTildeInPath」メソッドに置き換えられました。 サンプルコードも次のように変更してください。

import Foundation

// 標準出力の出力先
var path1 = NSString(string: "~/Desktop/stdout.txt").expandingTildeInPath

// 標準エラーの出力先
var path2 = NSString(string: "~/Desktop/stderr.txt").expandingTildeInPath

// 標準出力と標準エラーの出力先を変更する
_ = freopen(path1, "w", stdout)
_ = freopen(path2, "w", stderr)

// 文字列を出力する
print("print function")
NSLog("NSLog function")
CFShow("CFShow function")

Section 008

P.62, オプショナルチェイニング

プロパティ「capitalizedString」が「capitalized」に置き換えられました。サンプルコードも次のように変更してください。

import Foundation

// オプショナル変数を定義する
var name1: String?
var name2: String?

// 変数「name1」に代入する
name1 = "the programming language swift"

// 変数が「nil」以外ならプロパティ「capitalizedString」を取得する
var cap1 = name1?.capitalized
var cap2 = name2?.capitalized

// コンソールに値を出力する
print("cap1 : \(cap1)")
print("cap2 : \(cap2)")

Section 011

P.71 - 72, インクリメント・デクリメントについて

インクリメント演算子とデクリメント演算子は、Swift 3.0では削除されました。「+」演算子は「=」演算子、「--」演算子は「-=」演算子を使ったコードに置き換えるようにしてください。

P.77, 「&」を使ったポインタ参照について

関数の第1引数の外部引数名を省略した場合、Swift 3.0からは引数名が外部引数名として使われるように変わりました。省略する場合には「_ 」を指定する必要があります。そのため、次のように、関数の引数の前に「_ 」を追加してください。

import Foundation

// 読み込み専用のポインタを引数にした関数
func printPointer(_ pointer: UnsafePointer<Void>) {
    print("Readonly Pointer: \(pointer)")
}

// 読み書き可能なポインタを引数にした関数
func printMutablePointer(_ pointer: UnsafeMutablePointer<Void>) {
    print("ReadWrite Pointer: \(pointer)")
}

var intValue: UInt32 = 10

// 「intValue」へのポインタを読み込み専用のポインタとして取得する
printPointer(&intValue)

// 「intValue」へのポインタを読み書き可能なポインタとして取得する
printMutablePointer(&intValue)

P.78, 配列のポインタを取得するには

次のように、関数の引数の前に「_ 」を追加してください。

import Foundation

// 読み込み専用のポインタを引数にした関数
func printPointer(_ pointer: UnsafePointer<UInt8>, len: Int) {
    print("Readonly Pointer: \(pointer)")
    var str = "  "
    for i in 0 ..< len {
        str += String(format: "%02X ", pointer[i])
    }
    print(str)
}

// 読み書き可能なポインタを引数にした関数
func printMutablePointer(_ pointer: UnsafeMutablePointer<UInt8>, len: Int) {
    print("ReadWrite Pointer: \(pointer)")
    var str = "  "
    for i in 0 ..< len {
        str += String(format: "%02X ", pointer[i])
    }
    print(str)
}

// ポインタを取得する配列を定義する
var array: [UInt8] = [1, 2, 3, 4]

// 読み込み専用のポインタを取得して、関数を呼び出す
printPointer(array, len: 4)
printPointer(&array, len: 4)

// 読み書き可能なポインタを取得して、関数を呼び出す
printMutablePointer(&array, len: 4)

P.79, ポインタのキャストを行うには

「unsafeBitCast」関数の定義が次のように変更されています。

func unsafeBitCast<T, U>(_ x: T, to: U.Type) -> U

それに伴って、サンプルコードの「unsafeBitCast」関数の呼び出しで、第2引数に「to:」を追加してください。また、関数の第1引数の定義に「_ 」を追加してください。

import Foundation

func printPointer(_ pointer: UnsafePointer<Void>, len: Int) {
    // 「UInt8」のポインタに変換する
    let p = unsafeBitCast(pointer, to: UnsafePointer<UInt8>.self)

    // コンソールに出力する
    var str = ""
    for i in 0 ..< len {
        str += String(format: "0x%02X ", p[i])
    }

    print(str)

    // 「UInt16」へのポインタに変換する
    let p2 = unsafeBitCast(pointer, to: UnsafePointer<UInt16>.self)

    // コンソールに出力する
    str = ""
    for i in 0 ..< (len / sizeof(UInt16)) {
        str += String(format: "0x%04X ", p2[i])
    }

    print(str)

    // 「UInt32」へのポインタに変換する
    let p3 = unsafeBitCast(pointer, to: UnsafePointer<UInt32>.self)

    // コンソールに出力する
    str = ""
    for i in 0 ..< (len / sizeof(UInt32)) {
        str += String(format: "0x%08X ", p3[i])
    }

    print(str)
}

// ポインタを取得する配列を定義する
var array: [UInt16] = [0x1234, 0x5678, 0x9ABC, 0xDEF0]

// 「Void」へのポインタを取得して、関数を実行する
printPointer(array, len: array.count * sizeof(UInt16))

Section 012

P.82, 複数の条件分岐を行うには

次のように「foo」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する
func foo(_ i: Int) -> String
{
    // ... 省略 ...
}
// ... 省略 ...

Section 013

P.84, 「switch」について

次のように「printNum」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する
func printNum(_ i:Int) {
    // ... 省略 ...
}
// ... 省略 ...

P.85, 複数の値にヒットする「case」について

次のように「printStr」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する
func printStr(_ season: String) {
    // ... 省略 ...
}
// ... 省略 ...

P.86, C言語やObjective-Cとの違い

次のように「printNumber」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する
func printNumber(_ i: Int) {
    // ... 省略 ...
}
// ... 省略 ...

P.87, 範囲にヒットする「case」について

次のように「printStr」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する
func printStr(_ i: Int) {
    // ... 省略 ...
}
// ... 省略 ...

P.89, 「case」とタプルを組み合わせる

次のように「printStr」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する
func printStr(_ pair: (Int, String)) {
    // ... 省略 ...
}
// ... 省略 ...

P.90, 91, 値のバインディング

次のように「printStr」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する
func printStr(_ t: (Int, Int)) {
    // ... 省略 ...
}
// ... 省略 ...

P.91, 範囲とタプルを組み合わせる

次のように「printArea」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する (ここでは(-10, -10)-(10, 10)という範囲に限定している)
// 座標系は、X座標は右方向が正、Y座標は下方向が正としている
func printArea(_ t: (Int, Int)) {
    // ... 省略 ...
}
// ... 省略 ...

P.93, 複雑な条件にヒットする「case」について

次のように「printSignedValue」関数、「isEven」関数、「printEvenOddNumber」関数の第1引数の定義に「_ 」を追加してください。

// 関数を定義する
func printSignedValue(_ i: Int) {
    // ... 省略 ...
}
// ... 省略 ...
// 偶数かどうかを判定する関数を定義する
func isEven(_ i: Int) -> Bool {
    // ... 省略 ...
}

// 関数を定義する
func printEvenOddNumber(_ t: (Int, Int)) {
    // ... 省略 ...
}
// ... 省略 ...

Section 014

P.96, 「guard」を使ってオプショナル変数のアンラップを行う

次のように「check」関数の第1引数の定義に「_ 」を追加してください。

import Foundation

// 関数を定義する
func check(_ value: Int?) {
    // ... 省略 ...
}
// ... 省略 ...

P.97, 「guard」を使って必須条件を満たしているかをチェックする

次のように「printEvenValue」関数の第1引数の定義に「_ 」を追加してください。

import Foundation

// 偶数のみ出力する関数
func printEvenValue(_ values: [Int]) {
    // ... 省略 ...
}
// ... 省略 ...

Section 015,

P.98, 「for」を使ったループについて

解説している2種類の構文で、以下の構文を使った「for」ループは削除されました。そのため、この構文を使用しているコードは、後者のバインディングを使用した構文を使ったコードに置き換える必要があります。または、「while」や「repeat」を使ったコードに置き換えてください。

for 初期化; ループ条件; ループ変数の更新 {
    ループさせる処理
}

P.100, 無限ループを行う

Cスタイルの「for」が使用できなくなったので、無限ループは、次のように「while」を使って記述します。

// 変数を定義する
var i = 0

// 無限ループ
// (ループ条件を指定していない)
while true {
    // カウントを増やしつつ、文字列を出力
    print("\(i):LOOP")
    i += 1
}

Section 018

P.110, 「defer」について, P.111, defer」が有効になるタイミング

次のように「testDefer」関数の第1引数の定義に「_ 」を追加してください。

import Foundation

// 関数を定義する
func testDefer(_ i: Int) {
    // ... 省略 ...
}
// ... 省略 ...

P.111, 複数の「defer」について

次のように「sum」関数の関数の第1引数の定義に「_ 」を追加してください。

import Foundation

// 関数を定義する
func sum(_ i: Int) {
    // ... 省略 ...
}
// ... 省略 ...

P.113, 「guard」と組み合わせる

次のように、コードを変更してください。

import Foundation

func printLog(_ log: String, message: String? = nil) {

    // ファイルパスを取得する
    var path = ("~/Desktop/Log.txt" as NSString).expandingTildeInPath

    // ファイルがなければ空のファイルを作る
    let fm = FileManager()
    if !fm.fileExists(atPath: path) {
        fm.createFile(atPath: path, contents: nil, attributes: nil)
    }

    // ファイルを開く
    // 開けなかったときは終了
    print("Open the log file")
    guard let fh = FileHandle(forUpdatingAtPath: path) else {
        print("Couldn't open the log file")
        return
    }

    // ファイルポインタを末端に移動
    fh.seekToEndOfFile()

    // ファイルを開けたので、これ以降は、スコープを抜けるときはファイルを閉じる
    defer {
        // スコープを抜けるときはファイルを閉じる
        print("Close the log file")
        fh.closeFile()
    }

    // 「log」の内容を出力する
    var data = log.data(using: String.Encoding.utf8)
    guard data != nil else {
        // UTF-8のデータを取得できなかった
        print("Couldn't encode with UTF-8")
        return
    }
    fh.write(data!)

    // 「message」の内容を出力する
    guard let msgStr = message else {
        // 「message」が指定されていない
        return
    }

    data = msgStr.data(using: String.Encoding.utf8)
    guard data != nil else {
        // UTF-8のデータを取得できなかった
        print("Couldn't encode with UTF-8")
        return
    }

    fh.write(data!)
}

// 関数を呼ぶ
printLog("Log 1\n")
printLog("Log 2: ", message:"Message\n")

Section 019

P.118, 引数について

ページ末尾に次の文章を追加してください。

Swift 3.0からは第1引数についても、特に指定しない場合は、引数名が外部引数名として使われるようになりました。

P.119, コード

次のように関数呼び出しを変更してください。

// ... 省略 ...

// 半径が2の円の面積を求める
let c1 = circle(r: 2)
print("circle(2) = \(c1)")

// 半径が11の円の面積を求める
let c2 = circle(r: 11)
print("cicle(11) = \(c2)")

// 上底2, 下底3, 高さ4の台形の面積を求める
let t1 = trapezoid(upper: 2, lower: 3, height: 4)
print("trapezoid(2, 3, 4) = \(t1)")

// 上底1, 下底5, 高さ11.5の台形の面積を求める
let t2 = trapezoid(upper: 1, lower: 5, height: 11.5)
print("trapezoid(1, 5, 11.5) = \(t2)")

P.120, 引数に値を返す

「inout」の構文が変わりました。次のように、引数名を先に書きます。

func 関数名(引数名: inout 引数の型)

サンプルコードも次のように変更してください。

// 関数を定義する
func inoutFunc(j: inout Int) {
    // 引数に値を設定する
    j = 10
}

// 変数を定義する
var i:Int = 0
print("BEFORE : \(i)")

// 関数を呼び出す
inoutFunc(j: &i)
print("AFTER  : \(i)")

P.122, P.123, 引数のデフォルト値を定義する

次のように関数の引数の定義に「_ 」を追加してください。

// 関数を定義する
// 引数を2つ定義する。デフォルト値は10とする
func printParam(_ i: Int = 10, j: Int = 10) {
    // 引数の値を出力する
    print("i = \(i), j = \(j)")
}

// 一部の引数のみデフォルト値を定義する
func printParam2(_ fname: String, lname: String,
    mname: String = "") {
        // 文字列を出力する
        print("\(fname) \(mname) \(lname)")
}
// ... 省略 ...

P.124, 可変引数を定義する

次のように関数の引数の定義に「_ 」を追加してくだい。

// 関数を定義する
func createNameList(_ names: String...) -> String {
    // ... 省略 ...
}
// ... 省略 ...

Section 020

P.126 - P.129, Swiftでの関数オブジェクトについて

次のように関数の引数の定義に「_ 」を追加してください。

// 関数「printArray」が呼び出す関数
// インデックス番号も出力する
func printItemWithIndex(_ index: Int, item: Any) {
    // ... 省略 ...
}

// 関数「printArray」が呼び出す関数
// インデックス番号を出力しない
func printItem(_ index: Int, item: Any) {
    // ... 省略 ...
}

// コールバック関数を使って、項目を出力する関数を定義する
func printArray(_ itemArray: [Any],
    itemWriter: (Int, Any) -> Void) {
        // ... 省略 ...
        }
}
// ... 省略 ...
// 関数オブジェクトを使って配列の内容を変形させる関数
// 「Int」の配列を引数にとる。
// 変形関数は「Int」を受け取り、「Int」を返す関数としている。
func transformArray(_ srcArray: [Int], t: (Int) -> Int) -> [Int] {
    // ... 省略 ...
}

// 値を3乗する関数を定義する
func cube(_ i: Int) -> Int {
    // ... 省略 ...
}

// 絶対値を返す関数を定義する
func absInt(_ i: Int) -> Int {
    // ... 省略 ...
}
// ... 省略 ...

Section 021

P.130, P.131, 関数を入れ子定義する

次のように関数の引数の定義に「_ 」を追加してください。

// 関数を定義する
func calcArray(_ targetArray: [Int]) -> (Int, Double) {
    // 合計を計算する
    func sumArray(_ intArray: [Int]) -> Int {
        // ... 省略 ...
    }

    // 平均を計算する
    func averageArray(_ intArray: [Int]) -> Double {
        // ... 省略 ...
    }
    // ... 省略 ...
}
// ... 省略 ...

Section 022

P.132, P133, 関数の引数でクロージャーを使用する

次のように関数の引数の定義に「_ 」を追加してください。

// 関数オブジェクトを使って配列の内容を変形させる関数
// 「Int」の配列を引数にとる。
// 変形関数は「Int」を受け取り、「Int」を返す関数としている。
func transformArray(_ srcArray: [Int], t: (Int) -> Int) -> [Int] {
    // ... 省略 ...
}

// 値を3乗する関数を定義する
func cube(_ i: Int) -> Int {
    // ... 省略 ...
}

// 絶対値を返す関数を定義する
func absInt(_ i: Int) -> Int {
    // ... 省略 ...
}
// ... 省略 ...

P.134, 値の参照保持とスコープ

デフォルトで外部引数名が定義されるので、関数の引数の定義から「dx」を一つ削除してください。

// 関数を定義する
// この関数は関数オブジェクトを返す
// 関数オブジェクトは「Double」を2つ入れたタプルを返す
func makeDriver(dx: Double, dy: Double) -> (() -> (Double, Double)) {
    // ... 省略 ...
}
// ... 省略 ...

P.135, 引数を省略定義

次のように関数の引数の定義に「_ 」を追加してください。

// 関数を定義する
// 引数「writer」は、「Int」受け取り「String」を返す関数オブジェクト
func printIntArray(_ intArray: [Int], writer: (Int) -> String) {
    ... 省略 ...
}
// ... 省略 ...

P.136, トレイリングクロージャー

次のように関数の引数の定義に「_ 」を追加してください。

// 関数を定義する
func printIntArray(_ intArray: [Int], writer: (Int) -> String) {
    // ... 省略 ...
}
// ... 省略 ...

P.141, 独自のコードで実行可能環境を指定するには

次のように、関数呼び出しに環境チェックコードを追加してください。

// ... 省略 ...

// 関数を呼ぶ
if #available(iOS 9.0, OSX 10.11, *) {
    myFunction()
}

Section 025

P.144, ONEPOINT

Swift 3.0では、「Swift API Design Guidelines」にしたがって、Enumのメンバーの名前は、アルファベットの小文字で始めるのが望ましいとなりました。本書では、このガイドラインが定義される前に書かれたため、大文字で始まっています。今後、書くコードではEnumのメンバーは小文字から始まるように定義するのが良いでしょう。

P.145, 列挙を使用するには

次のように関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func printColor(_ c: SignalColor) {
    // ... 省略 ...
}
// ... 省略 ...

P.147, 列挙を省略するには

次のように関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func printColor(_ c: SignalColor) {
    // ... 省略 ...
}
// ... 省略 ...

P.149-151, 「switch」「case」の条件分岐で関連値を取得するには

次のように関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func printStatus(_ status: Status) {
    // ... 省略 ...
}
// ... 省略 ....

Section 028

P.158, インスタンスを確保する

次のように関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func printBox(_ box1: Box, box2: Box, box3: Box) {
    // ここでは何もしない
}
// ... 省略 ...

Section 029

P.162-163, プロパティを使用するには

次のように関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func printBox(_ aBox: ShapeBox) {
    // ... 省略 ...
}
// ... 省略 ...

Section 034

P.185, メソッドの定義方法

次のようにcase文に「.」を追加してください。

// 列挙を定義する
enum Color {

    // メンバーを定義する
    case Red, Yellow, Blue

    // メソッドを定義する
    func name() -> String {
        // 自分自身が何であるかを知るには、「self」を使う
        switch self {
        case .Red:
            return "Red"
        case .Yellow:
            return "Yellow"
        case .Blue:
            return "Blue"
        }
    }
}
// ... 省略 ...

P.186 - P.187, 外部引数名について

次のように関数の引数の定義に「_ 」を追加してください。

class Rect {
    // ... 省略 ...
    func expandWidthBy(_ widthBy: Double, heightBy: Double) {
        // ... 省略 ...
    }
}
// ... 省略 ...

P.187 - P.188, 外部引数名を変更するには

次のように関数の引数の定義に「_ 」を追加してください。

class Rect {
    // ... 省略 ...
    func expandWidthBy(_ dx: Double, heightBy dy: Double) {
        // ... 省略 ...
    }
}
// ... 省略 ...
\(rt.x), \(rt.y), \(rt.width), \(rt.height)}")

P.189, 外部引数名を使わないようにするには

次のように関数の引数の定義に「_ 」を追加してください。

class Point {
    // ... 省略 ...
    func reset(_ dx: Double, _ dy: Double) {
        // ... 省略 ...
    }
}
// ... 省略 ...

P.190-191, 関数オブジェクトを引数に取るメソッドの定義

次のように関数の引数の定義に「_ 」を追加してください。

class MyArray {
    // ... 省略 ...
    func transform(_ t: (Int) -> Int) {
        // ... 省略 ...
    }
    // ... 省略 ...
}
// ... 省略 ...

P.191-193, タイプメソッドについて

次のように関数の引数の定義に「_ 」を追加してください。

enum SignalColor {
    // ... 省略 ...
    static func nextColor(_ curColor: SignalColor) -> SignalColor {
        // ... 省略 ...
    }
}

// ... 省略 ...

class Point {
    // ... 省略 ...
    class func differFrom(_ pt1: Point, toPoint: Point) -> (Int, Int) {
        return (toPoint.x - pt1.x, toPoint.y - pt1.y)
    }
}
// ... 省略 ...

Section 035

P.194, 構造体のメソッドでプロパティを変更する

次のように関数の引数の定義に「_ 」を追加してください。

// 構造体「Point」を定義する
struct Point {
    // ... 省略 ...
    mutating func moveTo(_ x: Double, _ y: Double) {
        // ... 省略 ...
    }
}
// ... 省略 ...

Section 036

P.195, メソッドでインスタンスを差し替える

次のように関数の引数の定義に「_ 」を追加してください。

// 構造体「Point」を定義する
struct Point {
    // ... 省略 ...
    mutating func moveByX(_ dx: Int, byY dy: Int) {
        // ... 省略 ...
    }
}
// ... 省略 ...

Section 037

P198-199, サブクラスを定義する

次のように関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func printPoint(_ pt: Point2D) {
    // ... 省略 ...
}
// ... 省略 ...

Section 039

P.205-206, 「=」演算子と組み合わせた省略演算子をオーバーロードするには

「inout」を書く場所が変わりました。次のように左辺値の前に記述します。

func 演算子(左辺値: inout 左辺値の型, 右辺値: 右辺値の型) {

}

サンプルコードも同様に変更します。

// ... 省略 ...
func += (vol: inout Volume, vol2: Volume) {
    // ... 省略 ...
}
// ... 省略 ...

P.206-208, インクリメントとデクリメントを定義する

「inout」を移動し、関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func += (vol: inout Volume, vol2: Volume) {
    // ... 省略 ...
}

prefix func ++ (vol: inout Volume) -> Volume {
    // ... 省略 ...
}

postfix func ++ (vol: inout Volume) -> Volume {
    // ... 省略 ...
}
// ... 省略 ...

P.209-210, 関係演算子をオーバーロードする

関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func printResult(_ msg: String, result: Bool) {
    // ... 省略 ...
}
// ... 省略 ...

Section 040

P.212-213, サブスクリプトを定義する

関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
class PeopleList {
    // ... 省略 ...
    func addPersonWithName(_ name: String) {
        peopleArray.append(Person(name: name))
    }
    // ... 省略 ...
}
// ... 省略 ...

P.213-214, 複数のインデックス番号に対応する

「Array」の「appendContentsOf」メソッドは、「append」メソッドに置き換えられました。次のように変更してください。

struct TwoDimensionInt {
    // ... 省略 ...
    init() {
        intArray.append(contentsOf: 0 ..< NumOfRow * NumOfCol)
    }
    // ... 省略 ...
}
// ... 省略 ...

Section 041

P.215, エクステンションを定義する

「String」の「componentsSeparatedByString」メソッドは、「components」メソッドに置き換えられました。次のように変更してください。

// ... 省略 ...
extension String {
    func initial() -> String {
        // スペースで文字列を分割する
        let words = self.components(separatedBy: " ")

        // ... 省略 ...
    }
}
// ... 省略 ...

P.216-218, エクステンションを使ってプロパティを追加するには

同様に「components」メソッドに置き換えてください。

// ... 省略 ...
extension String {

    var initial: String {
        get {
            // スペースで文字列を分割する
            let words = self.components(separatedBy: " ")

            // ... 省略 ...
        }
    }
}
// ... 省略 ...

Section 042

P.220-221, プロトコルを定義する

関数の引数の定義に「_ 」を追加してください。

// プロトコル「IndexList」を定義する
protocol IndexList {
    // ... 省略 ...
    mutating func addIndex(_ i: Int)
    // ... 省略 ...
}

// プロトコル「IndexList」を実装するクラス「IndexListImp」を定義する
class IndexListImp : IndexList {
    // ... 省略 ...
    func addIndex(_ i: Int) {
        self.internalArray.append(i)
    }
    // ... 省略 ...
}
// ... 省略 ...

P.222-223, 実装が必須ではないメソッドやプロパティを定義するには

各プロパティやメソッドにも「@objc」の指定が必須になりました。次のように追加してください。

// ... 省略 ...
@objc protocol Appearance {
    @objc optional var color: Int { get }
    @objc optional func invert()
}
// ... 省略 ...

P.223-225, エクステンションを使って既存の型にプロトコルの実装を追加するには

関数の引数の定義に「_ 」を追加し、「componentsSeparatedByString」メソッドを「components」メソッドに置き換えてください。

// ... 省略 ...
protocol Point2D {
    // ... 省略 ...
    mutating func setX(_ X: Int, Y: Int)
}

extension String : Point2D {
    var x: Int {
        get {
            // 「,」で分割した文字列を取り出す
            let tokens = self.components(separatedBy: ",")
            // ... 省略 ...
        }
    }

    var y: Int {
        get {
            // 「,」で分割した文字列を取り出す
            let tokens = self.components(separatedBy: ",")
            // ... 省略 ...
        }
    }

    mutating func setX(_ X: Int, Y: Int) {
        // ... 省略 ...
    }
}
// ... 省略 ...

P.227-229, プロトコルエクステンションの適用を制限する

「CollectionType」を「Collection」、「Generator.Element」を「Iterator.Element」に置き換えてください。

// ... 省略 ...
extension Collection where Iterator.Element : Shape {
    // ... 省略 ...
}
// ... 省略 ...

Section 043

P.230, ジェネリック関数を定義する

関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func greaterValue<T: Comparable>(_ v1: T, _ v2: T) -> T {
    // ... 省略 ...
}
// ... 省略 ...

Section 044

P.232, ジェネリックを使った構造体を定義する

「IntegerType」を「Integer」に置き換え、関数の引数の定義に「_ 」を追加してください。

struct Point2D<T: Integer> {
    // ... 省略 ...
    mutating func moveByX(_ X: T, byY: T) {
        // ... 省略 ...
    }

    func printProperty(_ msg: String) {
        // ... 省略 ...
    }
}
// ... 省略 ...

Section 045

P.234-236, ジェネリックを使ったクラスを定義する

メソッドの引数の定義に「_ 」を追加してください。

// ... 省略 ...
class LinkedList<ValueType> {
    // ... 省略 ...
    func addValue(_ v: ValueType) {
        // ... 省略 ...
    }
    // ... 省略 ...
}
// ... 省略 ...

Section 046

P.238-239, タイプパラメータに制約を付ける

構文が次のものに変わりました。

func 関数名<タイプパラメータ>(引数の定義) -> 戻り値の型 where 制約 {

}

サンプルコードもそれに合わせて変更してください。また「IntegerType」を「Integer」に置き換え、関数の引数の定義に「_ 」の追加を行ってください。

// ... 省略 ...
func printGreater<T>(_ v1: T, _ v2: T) where
    T: Comparable, T: Integer {
        // ... 省略 ...
}
// ... 省略 ...

P.239-240, アソシエーテッドタイプと組み合わせる

構文の変更に合わせてコードの変更と、関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func isEqualMyValue<T1: MyValue, T2: MyValue>(_ v1: T1, _ v2: T2) -> Bool where
    T1.ValueType == T2.ValueType,
    T1.ValueType: Equatable {
        return v1.value == v2.value
}
// ... 省略 ...

Section 047

P.241, エラー制御を実装する

「ErrorType」を「Error」に置き換え、関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
enum MyError: Error {
    case OutOfBounds
}

// 配列の指定した範囲内の合計を計算する関数
func sum(_ values: [Int], index: Int, length: Int) throws -> Int {
    // ... 省略 ...
}
// ... 省略 ...

P.243-244, エラー制御により投げられたエラーを無視するには

「ErrorType」を「Error」に置き換え、関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
enum MyError: Error {
    case OutOfBounds
}

// 配列の指定した範囲内の合計を計算する関数
func sum(_ values: [Int], index: Int, length: Int) throws -> Int {
    // ... 省略 ...
}
// ... 省略 ...

P.245-246, モジュール分割について

次のようにコードを変更してください。

// ... 省略 ...
public struct Rect {
    // ... 省略 ...

    // 「inout」の位置を変更し、引数「pt」の前に「_ 」を追加
    func getOrigin(_ pt: inout Point2D, sz: inout Size2D) {
        // ... 省略 ...
    }

    // 第1引数の外部引数名の指定を削除
    mutating func resize(width: Int, height: Int) {
        // ... 省略 ...
    }

    // 第1引数の外部引数名の指定を削除
    mutating func move(byX: Int, byY: Int) {
        // ... 省略 ...
    }
}

Section 050

P.252-253, インスタンスが指定したクラスかを調べる

関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func checkInstance(_ obj: AnyObject) {
    // ... 省略 ...
}
// ... 省略 ...

P.253-254, 構造体や列挙に対して調べる

関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func checkInstance(_ obj: Any) {
    // ... 省略 ...
}
// ... 省略 ...

Section 051

P.257, ダウンキャストを行う

// ... 省略 ...
func printMessage(_ obj: AnyObject) {
    // ... 省略 ...
}
// ... 省略 ...

P.258, 確実にダウンキャストができるときには「as!」を使う

関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
func printPoint(_ points: [Any]) {
    // ... 省略 ...
}
// ... 省略 ...

Section 053

P.260-261, インスタンスがメソッドを実装しているか調べる

「respondsToSelector」メソッドは「responds」メソッドに置き換えられました。 サンプルコードもメソッドの置き換えが必要です。また、関数の引数の定義に「_ 」を追加してください。

// ... 省略 ...
class Point2D : NSObject {
    // ... 省略 ...
    func moveToX(_ toX: Int, toY: Int) {
        // ... 省略 ...
    }
}

// インスタンスを確保する
var pt = Point2D()

// メソッド「reset」を実装しているか調べる
if pt.responds(to: #selector(Point2D.reset)) {
    print("pt responds to 'reset'")
} else {
    print("pt doesn't respond to 'reset'")
}

// メソッド「moveToX」を実装しているか調べる
// 引数のラベルも指定する必要がある
if pt.responds(to: #selector(Point2D.moveToX(_:toY:))) {
    print("pt responds to 'moveToX:toY:'")
} else {
    print("pt doesn't respond to 'moveToX'")
}

// メソッド「moveToX」を実装しているか調べる
// ラベルを指定しないと別のメソッドとして扱われてしまうので認識できない
if pt.responds(to: Selector("moveToX")) {
    print("pt responds to 'moveToX'")
} else {
    print("pt doesn't respond to 'moveToX'")
}

P.262-263, プロパティを持っているか調べるには

プロパティのアクセッサメソッドに対するセレクタの取得方法は次のような構文を使うようになりました。

// 取得用メソッド
#selector(getter: 構造体.プロパティ)
#selector(getter: クラス.プロパティ)

// 設定用メソッド
#selector(setter: 構造体.プロパティ)
#selector(setter: クラス.プロパティ)

ただし、これらの構文は構造体やクラスが、実際にそのプロパティを定義している時にしか使用できません。定義されていないプロパティに対して記述すると、コンパイル時にエラーになります。本来はコンパイル時にエラーになることで、間違ったコードを防ぐことができ、安全性が高まるというものですが、何らかの理由で定義されていないときは、従来の構文を使用します。

サンプルコードもそれに合わせて次のように変更してください。また、「respondsToSelector」メソッドの置き換え、関数の引数の定義に「_ 」への追加も行ってください。

// ... 省略 ...
func implementStatus(_ obj: AnyObject,
    getSel: Selector, setSel: Selector) -> String {
        // ... 省略 ...
}

// インスタンスを確保する
var pt = Point3D()

// プロパティ「locX」「locY」「locZ」について取得用メソッドと
// 設定用メソッドが定義されているかを調べる
// プロパティ「locX」について調べる
var status = implementStatus(pt, getSel: #selector(getter: Point3D.locX), setSel: #selector(setter: Point3D.locX))
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 054

P.265, 「NSStringFromClass」を使う方法について

プロパティ「dynamicType」は「type」を使うように変わりました。

type(of: オブジェクト)

また、クラスタイプを取得するときは、プロパティ「self」を使用します。

クラス.self

サンプルコードもそれに合わせて変更してください。

// ... 省略 ...
var str1 = NSStringFromClass(type(of: pt))

// クラスタイプを指定してクラス名を取得する
var str2 = NSStringFromClass(Point.self)
// ... 省略 ...

P.266, Objective-Cでのクラス名を指定している場合の動作について

プロパティ「dynamicType」を置き換えてください。

// ... 省略 ...
print("sz is \(NSStringFromClass(type(of: sz)))")

Section 055

P.267, クラス名からクラスタイプを取得する

次のように外部引数名の指定を削除してください。

// ... 省略 ...
class Point : NSObject {
    // ... 省略 ...
    class func newPoint(x: Int, y: Int) -> Point {
        // ... 省略 ...
    }
}
// ... 省略 ...

P.269, メソッドを文字列化する

次のようにメソッドの引数の定義に「_ 」を追加してください。

// ... 省略 ...
class MyClass : NSObject {
    // ... 省略 ...
    func calc(_ x: Int, y: Int, z: Int) -> Int {
        // ... 省略 ...
    }
    // ... 省略 ...
}
// ... 省略 ...

Section 057

文字列からメソッドを取得する

次のようにメソッドの引数の定義に「_ 」を追加し、「respondsToSelector」メソッド、「dynamicType」プロパティの置き換えを行ってください。

// ... 省略 ...
class MyClass : NSObject {
    // ... 省略 ...
    func calc(_ x: Int, y: Int, z: Int) -> Int {
        // ... 省略 ...
    }
    // ... 省略 ...
}

// ... 省略 ...

// インスタンスメソッドが実装されているか調べる
if obj.responds(to: sel) {
    print("obj responds to \(sel)")
} else {
    print("obj doesn't respond to \(sel)")
}

// タイプメソッドが実装されているか調べる
if type(of: obj).responds(to: sel2) {
    print("type of obj responds to \(sel2)")
} else {
    print("type of obj doesn't respond to \(sel2)")
}

Section 058

P.273, KVC経由でプロパティにアクセスする

「valueForKey」メソッドは「value」メソッドに置き換わりました。

func value(forKey key: String) -> Any?

サンプルコードは次のように変更してください。

// ... 省略 ...
var x = pt.value(forKey: "x") as! Int?
var y = pt.value(forKey: "y") as! Int?
// ... 省略 ...

P.275-276, キーパスを使用する

「valueForKeyPath」メソッドは「value」メソッドに置き換わりました。

func value(forKeyPath keyPath: String) -> Any?

サンプルコードは次のように変更してください。

// ... 省略 ...
var x1 = line.value(forKeyPath: "startPoint.x") as! Int?
var y1 = line.value(forKeyPath: "startPoint.y") as! Int?
var x2 = line.value(forKeyPath: "endPoint.x") as! Int?
var y2 = line.value(forKeyPath: "endPoint.y") as! Int?
// ... 省略 ...

P.276-277, 存在しないキーに対して行った場合

「valueForUndefinedKey」メソッドは「value」メソッドに置き換わりました。

func value(forUndefinedKey key: String) -> Any?

サンプルコードは次のように変更してください。

// ... 省略 ...
class Point2D : NSObject {
    // ... 省略 ...
    override func value(forUndefinedKey key: String) -> Any? {
        switch key {
        // ... 省略 ...
        default:
            // それ以外のときはスーパークラスの処理を呼ぶ
            return super.value(forUndefinedKey: key)
        }
    }
}
// ... 省略 ...

Section 059

P.278-279, KVOを使ってプロパティの変更を監視する

「observeValueForKeyPath」メソッドは「observeValue」メソッド、「NSKeyValueChangeOldKey」は「NSKeyValueChangeKey.oldKey」、「NSKeyValueChangeNewKey」は「NSKeyValueChangeKey.newKey」に置き換わりました。また、Enumの定義は先頭が小文字に変わりました。

func observeValue(forKeyPath keyPath: String?
  ob object: Any?,
  change: [NSKeyValueChangeKey : Any]?,
  context: UnsafeMutableRawPointer?)

サンプルコードは次のようにコードを変更してください。

// ... 省略 ...
class Observer : NSObject {

    // 監視しているプロパティが変更されたときに呼ばれるメソッド
    override func observeValue(forKeyPath keyPath: String?,
        of object: Any?, change: [NSKeyValueChangeKey : Any]?,
        context: UnsafeMutableRawPointer?) {

            guard let changeDict = change else {
                return
            }

            // 変更前の値を取得する
            let prevValue = changeDict[NSKeyValueChangeKey.oldKey] as! Int?

            // 変更後の値を取得する
            let newValue = changeDict[NSKeyValueChangeKey.newKey] as! Int?

            // コンソールに出力する
            print("\(keyPath) = \(prevValue) => \(newValue)")
    }
    // ... 省略 ...
}

// ... 省略 ...

notifier.addObserver(observer, forKeyPath: "intValue",
    options: [.new, .old],
    context: nil)

// ... 省略 ...

Section 060

P.281, 型の大きさを取得する

「sizeof」は「MemoryLayout」の「size」プロパティを使用するように変更になりました。

static var size: Int

サンプルコードは次のように変更してください。

// ... 省略 ...
var size1 = MemoryLayout<UInt8>.size
var size2 = MemoryLayout<UInt16>.size
var size3 = MemoryLayout<UInt32>.size
var size4 = MemoryLayout<Rect>.size
// ... 省略 ...

P.282, インスタンスの大きさを取得するには

「sizeofValue」関数は削除されました。

P.283, 配列のインスタンスの大きさの取得について

「sizeofValue」関数は削除されました。下側のコードは次のように変更できます。

// ... 省略 ...
var size = MemoryLayout<UInt16>.size * array.count
// ... 省略 ...

Section 062

P.289, メソッドを使って文字列を結合するには

「appendContentsOf」メソッドは「append」メソッドに置き換わりました。

mutating func append<S : Sequence where S.Iterator.Element == Character>(
  contentsOf newElements: S)

サンプルコードは次のように変更してください。

// 変数を定義する
var str = "Programming "

// 「appendContentsOf」メソッドを使って追加する
str.append("Language")

// コンソールに出力する
print(str)

P.289-290, 文字を追加するには

「UnicodeScalar」を引数にした「append」メソッドは削除されました。ユニコードのスカラー値を指定したい場合は、文字列リテラルを使って、「String」にして追加します。

// ... 省略 ...
str.append("\u{261E}")
// ... 省略 ...

P.290-291, 文字列を途中に挿入するには

「rangeOfString」メソッドを「range」メソッド、「insertContentsOf」メソッドを「insert」メソッドに置き換えてください。「insert」メソッドの2番目の引数の外部引数名が変わっています。

mutating func insert
<S : Collection where S.Iterator.Element == Character>(
  contentsOf newElements: S, at i: Index)

サンプルコードは次のようにコードを変更してください。

// ... 省略 ...

var range = str.range(of: "Swift")

// 見つかった位置に挿入する
str.insert(contentsOf: "Language ".characters, at: range!.lowerBound)

// 先頭に「"」を挿入する
str.insert(Character("\""), at: str.startIndex)

// ... 省略 ...

P.291-292, 「NSMutableString」クラスを使って文字列を結合・挿入する

「insertString」と「insertContentsOf」メソッドを「insert」メソッド、「appendString」メソッドを「append」メソッド、外部引数名の「atIndex」を「at」に置き換えてください。また、任意のインデックスは「index」メソッドにオフセット値を渡して取得できるようになりました。

func insert(_ aString: String, at loc: Int)
func append(_ aString: String)

サンプルコードは、次のようにコードを変更してください。

import Foundation

// 文字列を「NSMutableString」クラスで確保する
var str = NSMutableString(string: "Programming Swift")

// 「String」で確保する
var str2 = "Programming Swift"

// 「Language 」を「Swift」の前に挿入する
// 「Swift」はインデックス番号12の位置。
str.insert("Language ", at: 12)
str2.insert(contentsOf: "Language ".characters,
    at: str2.index(str2.startIndex, offsetBy: 12))

// 先頭に「"」を挿入する
str.insert("\"", at: 0)
str2.insert("\"", at: str2.startIndex)

// 末尾に「"」を追加する
str.append("\"")
str2.append(Character("\""))

// コンソールに出力する
print(str)
print(str2)

P.292, 任意のインデックスを取得するには

「advanceBy」は削除されました。「index」メソッドを使って取得します。「index」メソッドは次のように定義されています。

public func index(_ i: Index, offsetBy n: IndexDistance) -> Index

P.294, テキストエンコーディング(文字コード)を指定して長さを取得するには

「lengthOfBytesUsingEncoding」メソッドは「lengthOfBytes」に置き換えられました。次のようにコードを変更してください。

// ... 省略 ...

// UTF-8での長さを取得する
let lenInUTF8 = str.lengthOfBytes(using: String.Encoding.utf8)

// UTF-16での長さを取得する
let lenInUTF16 = str.lengthOfBytes(using: String.Encoding.utf16)

// Shift JISでの長さを取得する
let lenInSJIS = str.lengthOfBytes(using: String.Encoding.shiftJIS)

// ... 省略 ...

Section 064

P.297, 任意の位置の文字を取得するには

「advancedBy」メソッドは「index」メソッドに置き換えてください。次のようにコードを変更してください。

// ... 省略 ...
let c2 = str.characters[str.characters.index(index, offsetBy: 1)]
// ... 省略 ...

Section 065

P.299, 文字列からテキストデータを取得する

「dataUsingEncoding」メソッドを「data」メソッド、「stringByExpandingTildeInPath」プロパティを「expandingTildeInPath」プロパティ、「writeToFile」メソッドを「write」メソッドに置き換えてください。

func data(using encoding: String.Encoding,
  allowLossyConversion: Bool = default) -> Data?

サンプルコードは次のようにコードを変更してください。

import Foundation

// 文字列を定義する
var str = "プログラミング言語Swift"

// テキストエンコーディングをEUCにしたテキストデータを作成する
var text = str.data(using: String.Encoding.japaneseEUC,
    allowLossyConversion: false)

// デスクトップに書き出す
let path = NSString(string: "~/Desktop/Test.txt").expandingTildeInPath
try! text?.write(to: URL(fileURLWithPath: path))

P.300, テキストエンコーディングについて

テキストエンコーディングは「NS」から始まるものではなく、「String」の「Encoding」の定数プロパティを使うように変更してください。

Section 066

P.301, 使用可能なテキストエンコーディングを取得する

「availableStringEncodings」メソッドはプロパティに、「localizedNameOfStringEncoding」メソッドは「localizedName」メソッドに置き換えてください。

static var availableStringEncodings: [String.Encoding] { get }
static func localizedName(of encoding: String.Encoding) -> String

サンプルコードは次のように変更します。

import Foundation

// 使用可能なテキストエンコーディングを取得する
var encodings = String.availableStringEncodings

// エンコーディングごとにループ
for enc in encodings {
    // エンコーディングの名前を取得する
    let name = String.localizedName(of: enc)

    // コンソールに出力する
    print(name)
}

Section 067

P.303, テキストデータから文字列を作成する

「stringByExpandingTildeInPath」プロパティを「expandingTildeInPath」プロパティ、「NSData」クラスを「Data」クラスに置き換えてください。次のように変更します。

import Foundation

// デスクトップに置いた「Test.txt」ファイルのデータを読み込む
let path = NSString(string: "~/Desktop/Test.txt").expandingTildeInPath

// 読み込んだデータから文字列を取得する
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
    // 文字列を作成する
    var str = String(data: data, encoding: String.Encoding.shiftJIS)

    if str != nil {
        // コンソールに出力する
        print(str!)
    }
}

Section 068

文字列からC文字列を作成する

「cStringUsingEncoding」メソッドを「cString」メソッドに置き換えてください。

func cString(using encoding: String.Encoding) -> [CChar]?

サンプルコードは次のように変更します。

// ... 省略 ...
var cstr = str.cString(using: String.Encoding.utf8)
// ... 省略 ...

Section 069

P.307-308, C文字列から文字列を作成する

外部引数名の先頭文字が小文字に変わっています。また、C言語の関数から返された値は、オプショナル変数になっているので、アンラップを追加します。

init?(cString: UnsafePointer<CChar>, encoding enc: String.Encoding)

サンプルコードは次のようにコードを変更してください。

// ... 省略 ...
var str = String(cString: cstr!, encoding: String.Encoding.utf8)
// ... 省略 ...

Section 070

P.310, 文字列をファイルに書き出す

「stringByExpandingTildeInPath」プロパティを「expandingTildeInPath」プロパティ、「writeToFile」メソッドを「write」メソッドに置き換えてください。

func write(toFile path: String,
  atomically useAuxiliaryFile: Bool, encoding enc: String.Encoding) throws

サンプルコードは次のように変更します。

// ... 省略 ...
let path = NSString(string: "~/Desktop/SJIS.txt").expandingTildeInPath

do {
    // シフトJISでファイルに書き込む
    try str.write(toFile: path, atomically: true, encoding: String.Encoding.shiftJIS)
    print("Successed")
} catch let error as NSError {
    // 書き込みに失敗したとき
    print("Failed: \(error)")
}

P.311, 書き込み先をURLで指定するには

「stringByExpandingTildeInPath」プロパティを「expandingTildeInPath」プロパティ、「writeToURL」メソッドを「write」メソッドに置き換えてください。

func write(to url: URL,
  atomically useAuxiliaryFile: Bool, encoding enc: String.Encoding) throws

サンプルコードは次のように変更します。

// ... 省略 ...
let path = NSString(string: "~/Desktop/SJIS_URL.txt").expandingTildeInPath
let url = URL(fileURLWithPath: path, isDirectory: false)

do {
    // シフトJISでファイルに書き込む
    try str.write(to: url, atomically: true, encoding: String.Encoding.shiftJIS)
    print("Successed")
} catch let error as NSError {
    print("Failed: \(error)")
}

Section 071

P.312, ファイルから文字列を読み込む

「stringByExpandingTildeInPath」プロパティを「expandingTildeInPath」、定数の置き換えを行ってください。次のように変更します。

import Foundation

// 読み込み先のファイルパス
let path = NSString(string: "~/Desktop/SJIS.txt").expandingTildeInPath

// シフトJISでファイルから読み込む
do {
    var str = try String(contentsOfFile: path,
        encoding: String.Encoding.shiftJIS)

    // コンソールに出力する
    print(str)
} catch let error as NSError {
    // 失敗したとき
    print("Failed: \(error)")
}

P.313, 読み込み先をURLで指定するには

「stringByExpandingTildeInPath」プロパティを「expandingTildeInPath」、定数の置き換えを行ってください。次のように変更します。

import Foundation

// 読み込み先のURL
let path = NSString(string: "~/Desktop/SJIS.txt").expandingTildeInPath
var url = URL(fileURLWithPath: path, isDirectory: false)

do {
    // シフトJISでファイルから読み込む
    var str = try String(contentsOf: url,
        encoding: String.Encoding.shiftJIS)

    // コンソールに出力する
    print(str)
} catch let error as NSError {
    // 失敗したとき
    print("Failed: \(error)")
}

Section 072

P.317-318, 置き換える値を配列で指定するには

「CVarArgType」を「CVarArg」に置き換えてください。次のように変更します。

// ... 省略 ...
let valueArray: [CVarArg] = [128, 255]
// ... 省略 ...

318-319, 書式を指定して文字列を結合するには

「stringByAppendingFormat」メソッドを「appendingFormat」メソッドに置き換えて、「as NSString」を追加してください。

func appendingFormat(_ format: String, _ arguments: CVarArg...) -> String

サンプルコードは次のように変更します。

// ... 省略 ...
str = str.appendingFormat(format, 128, 255)

// 「str2」の内容を変更して結合する
str2.appendFormat(format as NSString, 128, 255)

// ... 省略 ...

Section 073

P.320, 文字列を大文字に変換する

「uppercaseString」プロパティは「uppercased」メソッドに置き換えられました。

func uppercased() -> String

サンプルコードは次のように変更してください。

// ... 省略 ...
let newStr = srcStr.uppercased()
// ... 省略 ...

Section 074

P.321, 文字列を小文字に変換する

「lowercaseString」プロパティは「lowercased」メソッドに置き換えられました。

func lowercased() -> String

サンプルコードは次のように変更してください。

// ... 省略 ...
let newStr = srcStr.lowercased()
// ... 省略 ...

Section 075

P.322, 文字列の単語ごとの先頭を大文字にする

「capitalizedString」プロパティは「caplitalized」プロパティに置き換えられました。

var capitalized: String { get }

サンプルコードは次のように変更してください。

// ... 省略 ...
let newStr = srcStr.capitalized
// ... 省略 ...

Section 078

P.325, 文字列を指定した文字列で区切った配列を作成する

「componentsSeparatedByString」メソッドは「components」メソッドに置き換えられました。

func components(separatedBy separator: String) -> [String]

サンプルコードは次のように変更してください。

// ... 省略 ...
let components = str.components(separatedBy: ",")
// ... 省略 ...

P.326-327, 指定したキャラクタセットで文字列を分割するには

「NSMutableCharacterSet」クラスではなく、「CharacterSet」を使うように変更します。サンプルコードは次のように変更してください。

import Foundation

// 分割元の文字列を定義する
let str = "1 Programming,2 Swift,3 逆引き,4 ハンドブック,5 Book"

// 「,」もしくはホワイトスペース文字で文字列を分割するため、
// ホワイトスペース文字のキャラクタセットを取得する。
var charSet = CharacterSet.whitespaces

// 「,」を追加する
charSet.insert(charactersIn: ",")

// 作ったキャラクタセットで文字列を分割する
let components = str.components(separatedBy: charSet)

// 分割した配列をコンソールに出力する
for component in components {
    print(component)
}

Section 079

P.328, 部分文字列を作成する

「substringWithRange」メソッドは「substring」メソッドに置き換えられました。「advancedBy」メソッドは「index」メソッドを使うように変更します。

func substring(with aRange: Range<Index>) -> String

サンプルコードは次のように変更してください。

// ... 省略 ...
let start = srcStr.characters.index(srcStr.startIndex, offsetBy: 5)
let end = srcStr.characters.index(srcStr.startIndex, offsetBy: 8)
let str = srcStr.substring(with: start ..< end)
// ... 省略 ...

P.329, 先頭から指定した長さの部分文字列を作成する

「substringToIndex」メソッドは「substring」メソッドに置き換えられました。

func substring(to index: Index) -> String

サンプルコードは次のように変更してください。

// ... 省略 ...
let str = srcStr.substring(to: srcStr.characters.index(srcStr.startIndex, offsetBy: 5))
// ... 省略 ...

P.329-330, 指定したインデックス以降の部分文字列を作成する

「substringFromIndex」メソッドは「substring」メソッドに置き換えられました。

func substring(from index: Index) -> String

サンプルコードは次のように変更してください。

// ... 省略 ...
let str = srcStr.substring(
    from: srcStr.characters.index(srcStr.startIndex, offsetBy: 8))
// ... 省略 ...

Section 080

P.331, 文字がキャラクタセットに含まれるか調べる

「NSCharacterSet」クラスの代わりに「CharacterSet」構造体を使用し、「contains」メソッドを使って文字がキャラクタセットに含まれる調べるように変更してください。

func contains(_ member: UnicodeScalar) -> Bool

サンプルコードは次のように変更してください。

import Foundation

// 調べる対象の文字列を定義する
let str = "A0$"

// 数字に対するキャラクタセットを取得
var charSet = CharacterSet.decimalDigits

// 一文字ずつチェックする
for c in str.unicodeScalars {
    // キャラクタセットに含まれるか調べる
    let b = charSet.contains(c)

    // コンソールに出力する
    print("\(c) \(b)")
}

P.332, 定義済みのキャラクタセットを取得するには

「CharacterSet」構造体のタイププロパティを使って、定義済みのキャラクタセットを取得するように変更してください。対応するタイププロパティは次の通りです。

public static var controlCharacters: CharacterSet { get }
public static var whitespaces: CharacterSet { get }
public static var whitespacesAndNewlines: CharacterSet { get }
public static var decimalDigits: CharacterSet { get }
public static var letters: CharacterSet { get }
public static var lowercaseLetters: CharacterSet { get }
public static var uppercaseLetters: CharacterSet { get }
public static var nonBaseCharacters: CharacterSet { get }
public static var alphanumerics: CharacterSet { get }
public static var decomposables: CharacterSet { get }
public static var illegalCharacters: CharacterSet { get }
public static var punctuationCharacters: CharacterSet { get }
public static var capitalizedLetters: CharacterSet { get }
public static var symbols: CharacterSet { get }
public static var newlines: CharacterSet { get }

P.333, キャラクタセットの内容を変更するには

「CharacterSet」構造体のメソッドを使用するように変更してください。対応するメソッドは次の通りです。

init(charactersIn range: Range<UnicodeScalar>)
init(charactersIn string: String)
mutating func insert(charactersIn range: Range<UnicodeScalar>)
mutating func remove(charactersIn range: Range<UnicodeScalar>)
mutating func insert(charactersIn string: String)
mutating func remove(charactersIn string: String)
mutating func formUnion(_ other: CharacterSet)
mutating func formIntersection(_ other: CharacterSet)
mutating func invert()

Section 081

P.335, キャラクタセットを使って分割する方法について

次のように「CharacterSet」構造体を使ったコードに変更してください。

// ... 省略 ...
var charSet = CharacterSet.newlines

// キャラクタセットを使って分割する
var lines = srcStr.components(separatedBy: charSet)

// ... 省略 ...

Section 082

P.336, 文字列を検索する

「rangeOfString」メソッドは「range」メソッドに置き換えられました。

func range(of aString: String, options mask: CompareOptions = default, range searchRange: Range<Index>? = default, locale: Locale? = default) -> Range<Index>?

サンプルコードは次のように変更してください。

// ... 省略 ...

// 「逆引き」を検索する
var range = text.range(of: "逆引き")

// 「iOS」を検索する
var range2 = text.range(of: "iOS")

// ... 省略 ...

P.337-338, 「NSString」クラスの「rangeOfString」メソッドについて

「rangeOfString」メソッドは「range」メソッドに置き換えられました。

func range(of searchString: String) -> NSRange

func range(of searchString: String, options mask: NSString.CompareOptions = []) -> NSRange

func range(of searchString: String, options mask: NSString.CompareOptions = [], range rangeOfReceiverToSearch: NSRange) -> NSRange

func range(of searchString: String, options mask: NSString.CompareOptions = [], range rangeOfReceiverToSearch: NSRange, locale: Locale?) -> NSRange

サンプルコードは次のように変更してください。

// ... 省略 ...

// 「逆引き」を検索する
var range = text.range(of: "逆引き")

// 「iOS」を検索する
var range2 = text.range(of: "iOS")

// ... 省略 ...

P.338, 検索する方向を指定するには

「BackwardsSearch」は「backwards」に置き換えられました。

static var backwards: NSString.CompareOptions { get }

サンプルコードは次のように変更してください。

// ... 省略 ...
var range = text.range(of: "Swift",
    options: NSString.CompareOptions.backwards)

var range2 = text2.range(of: "Swift",
    options: NSString.CompareOptions.backwards)
// ... 省略 ...

P.339-340, 前後の文字列を検索するには

次のようにサンプルコードを変更してください。

import Foundation

// 文字列を定義する
let text = "Swift Swift Swift"
let text2: NSString = "Swift Swift Swift"

// 最初は全体を検索範囲にする
var range = text.startIndex ..< text.endIndex

// 「break」するまでループする
while true {
    // 変数「range」の範囲を検索する
    var found = text.range(of: "Swift",
        options: NSString.CompareOptions(), range: range)

    // 見つからなかったらループ中断
    if found == nil {
        break
    }

    // 見つかった位置を出力
    print(found)

    // 検索範囲の開始位置を、直前に見つかった位置の後ろに設定する
    range = found!.upperBound ..< text.endIndex
    if !range.isEmpty {
        // 一つ後ろにずらす
        range = text.index(range.lowerBound, offsetBy: 1) ..< text.endIndex
    } else {
        // 末尾に到達
        break
    }
}

// 「NSString」クラスの場合
// 最初は全体を検索範囲にする
var range2 = NSMakeRange(0, text2.length)

// 「break」するまでループする
while true {
    // 変数「range2」の範囲を検索する
    var found = text2.range(of: "Swift",
        options: NSString.CompareOptions(), range: range2)

    // 見つからなかったらループ中断
    if found.location == NSNotFound {
        break
    }

    // 見つかった位置を出力
    print(NSStringFromRange(found))

    // 検索範囲の開始位置を、直前に見つかった位置の後ろに設定する
    range2.location = found.location + found.length
    range2.length = text2.length - range2.location
}
import Foundation

// 文字列を定義する
let text = "Swift Swift Swift"
let text2: NSString = "Swift Swift Swift"

// 最初は全体を検索範囲にする
var range = text.startIndex ..< text.endIndex

// 「break」するまでループする
while true {
    // 変数「range」の範囲を検索する
    var found = text.range(of: "Swift",
        options: .backwards, range: range)

    // 見つからなかったらループ中断
    if found == nil {
        break
    }

    // 見つかった位置を出力
    print(found)

    // 検索範囲の終了位置を、見つかった位置の先頭に設定する
    range = range.lowerBound ..< found!.lowerBound
}

// 「NSString」クラスの場合
// 最初は全体を検索範囲にする
var range2 = NSMakeRange(0, text2.length)

// 「break」するまでループする
while true {
    // 変数「range2」の範囲を検索する
    var found = text2.range(of: "Swift",
        options: .backwards, range: range2)

    // 見つからなかったらループ中断
    if found.location == NSNotFound {
        break
    }

    // 見つかった位置を出力
    print(NSStringFromRange(found))

    // 検索範囲の終了位置を、見つかった位置の先頭に設定する
    range2.length = found.location
}

P.342, 大文字・小文字を無視するには

「CaseInsensitiveSearch」は「caseInsensitive」に置き換えられました。

static var caseInsensitive: NSString.CompareOptions { get }

サンプルコードは次のように変更してください。

import Foundation

// 文字列を定義する
let text = "swift SWIFT Swift"
let text2: NSString = "swift SWIFT Swift"

// 最初は全体を検索範囲にする
var range = text.startIndex ..< text.endIndex

// 「break」するまでループする
while true {
    // 変数「range」の範囲を検索する
    // 大文字小文字を無視するので「CaseInsensitiveSearch」を指定する
    var found = text.range(of: "Swift",
        options: .caseInsensitive, range: range)

    // 見つからなかったらループ中断
    if found == nil {
        break
    }

    // 見つかった位置を出力
    print(found)

    // 検索範囲の開始位置を更新する
    range = found!.upperBound ..< range.upperBound
    if !range.isEmpty {
        // 一つ後ろにずらす
        range = text.index(after: range.lowerBound) ..< range.upperBound
    } else {
        // 末尾に到達
        break
    }
}

// 「NSString」クラスの場合
// 最初は全体を検索範囲にする
var range2 = NSMakeRange(0, text2.length)

// 「break」するまでループする
while true {
    // 変数「range2」の範囲を検索する
    // 大文字小文字を無視するので「CaseInsensitiveSearch」を指定する
    var found = text2.range(of: "Swift",
        options: .caseInsensitive, range: range2)

    // 見つからなかったらループ中断
    if found.location == NSNotFound {
        break
    }

    // 見つかった位置を出力
    print(NSStringFromRange(found))

    // 検索範囲の開始位置を更新する
    range2.location = found.location + found.length
    range2.length = text2.length - range2.location
}

P.344, 正規表現を使って検索するには

「RegularExpressionSearch」は「regularExpression」に置き換えられました。

static var regularExpression: NSString.CompareOptions { get }

サンプルコードは次のように変更してください。

// ... 省略 ...
var range = text.range(of: "[0-9]+", options: .regularExpression)
var range2 = text2.range(of: "[0-9]+", options: .regularExpression)

// 結果を出力する
print(range)
print(NSStringFromRange(range2))

Section 083

P.345, 文字列の一部を置き換える

「replaceRange」メソッドは「replaceSubrange」メソッド、「replaceCharactersInRange」メソッドは「replaceCharacters」メソッドに置き換えられました。

// 「String」の一部を置き換えるメソッド
mutating func replaceSubrange(_ bounds: Range<Index>, with newElements: String)

// 「NSMutableString」クラスの一部を置き換えるメソッド
func replaceCharacters(in range: NSRange, with aString: String)

サンプルコードは次のように変更してください。

// ... 省略 ...

var range = str1.range(of: "Objective-C")

// 見つかった範囲を「Swift」に置き換える
if range != nil {
    str1.replaceSubrange(range!, with: "Swift")
}

// 「NSMutableString」クラスの場合
// 「Objective-C」を検索する
var range2 = str2.range(of: "Objective-C")

// 見つかった範囲を「Swift」に置き換える
if range2.location != NSNotFound {
    str2.replaceCharacters(in: range2, with: "Swift")
}

// ... 省略 ...

P.346, 文字列の一部を削除する

サンプルコードを次のように変更してください。

// ... 省略 ...

var range = str1.range(of: "Objective-C")

// 見つかった範囲を空文字列に置き換える
if range != nil {
    str1.replaceSubrange(range!, with: "")
}

// 「NSMutableString」クラスの場合
// 「Objective-C」を検索する
var range2 = str2.range(of: "Objective-C")

// 見つかった範囲を空文字列に置き換える
if range2.location != NSNotFound {
    str2.replaceCharacters(in: range2, with: "")
}

// ... 省略 ...

Section 084

P.347-348, 文字列を比較する

「compare」メソッド戻り値は「NSComparisonResult」から「ComparisonResult」に変わっています。

func compare(_ aString: String, options mask: CompareOptions = default, range: Range<Index>? = default, locale: Locale? = default) -> ComparisonResult

「ComparisonResult」は「enum」になっていて、以下のメンバーが定義されています。

  • orderedAscending

  • orderedSame

  • orderedDescending

サンプルコードは次のように変更してください。

import Foundation

// 「NSComparisonResult」を文字列で返す関数
func strOfResult(_ result: ComparisonResult) -> String {
    switch result {
    case .orderedAscending:
        return "OrderedAscending"
    case .orderedDescending:
        return "OrderedDescending"
    case .orderedSame:
        return "OrderedSame"
    }
}
// ... 省略 ...

P.349, 大文字・小文字を区別せずに比較するには

「CaseInsensitiveSearch」は「caseInsensitive」に置き換えられました。

static var caseInsensitive: NSString.CompareOptions { get }

サンプルコードは次のように変更してください。

import Foundation

// 「NSComparisonResult」を文字列で返す関数
func strOfResult(_ result: ComparisonResult) -> String {
    switch result {
    case .orderedAscending:
        return "OrderedAscending"
    case .orderedDescending:
        return "OrderedDescending"
    case .orderedSame:
        return "OrderedSame"
    }
}
// ... 省略 ...
var result = str1.compare(str2, options: .caseInsensitive)
// ... 省略 ...

P.350, 文字列の一部を比較するには

インデックスは、「String」の「index」メソッドを使って取得するように変更します。サンプルコードを次のように変更してください。

import Foundation

// 「NSComparisonResult」を文字列で返す関数
func strOfResult(_ result: ComparisonResult) -> String {
    switch result {
    case .orderedAscending:
        return "OrderedAscending"
    case .orderedDescending:
        return "OrderedDescending"
    case .orderedSame:
        return "OrderedSame"
    }
}

// 比較する文字列を定義する
var str = "1. Swift"

// インデックス番号3から5文字の範囲を比較する
let start = str.index(str.startIndex, offsetBy: 3)
let end = str.index(str.startIndex, offsetBy: 8)
var range = start ..< end

// 比較する
var result = str.compare("Swift", options: [], range: range)

// 結果を出力する
print(strOfResult(result))

Section 085

P.353, 16進数の文字列を数値に変換するには

「NSScanner」クラスではなく「Scanner」クラスを使うように変更します。16進数を読み込むメソッドには次のようなものがあります。

func scanHexInt32(_ result: UnsafeMutablePointer<UInt32>?) -> Bool
func scanHexInt64(_ result: UnsafeMutablePointer<UInt64>?) -> Bool
func scanHexFloat(_ result: UnsafeMutablePointer<Float>?) -> Bool
func scanHexDouble(_ result: UnsafeMutablePointer<Double>?) -> Bool

サンプルコードは次のように変更します。

import Foundation

// 変換前の文字列を定義する
var a = "0xFF"
var b = "g"

// 「NSScanner」を確保
var scanner = Scanner(string: a)

// 16進数として読み込む
var u: UInt32 = 0

if scanner.scanHexInt32(&u) {
    // 成功
    print("\(a) -> \(u)")
} else {
    // 失敗
    print("\(a) -> Failed")
}

// 「NSScanner」を確保
scanner = Scanner(string: b)

// 16進数として読み込む
if scanner.scanHexInt32(&u) {
    // 成功
    print("\(b) -> \(u)")
} else {
    // 失敗
    print("\(b) -> Failed")
}

Section 086

P.356, コンポーネントを結合してパス文字列を作るには

「pathWithComponents」メソッドは「path」メソッドに置き換えられました。

class func path(withComponents components: [String]) -> String

サンプルコードは次のように変更してください。

// ... 省略 ...

// コンポーネントの配列からパスを作る
var path = NSString.path(withComponents: components)

// コンソールに出力する
print(path)

Section 089

P.361, パス文字列にコンポーネントを追加する

「stringByAppendingPathComponent」メソッドは「appendingPathComponent」メソッドに置き換えられました。

func appendingPathComponent(_ str: String) -> String

サンプルコードは次のように変更してください。

// ... 省略 ...

// 配列に格納されているコンポーネントを順番に追加する
for component in components {
    // コンポーネントを追加する
    path = (path as NSString).appendingPathComponent(component)

    // コンソールに出力する
    print(path)
}

Section 090

P.363, パス文字列に拡張子を追加する

「stringByAppendingPathExtension」メソッドは「appendingPathExtension」メソッドに置き換えられました。

func appendingPathExtension(_ str: String) -> String?

サンプルコードは次のように変更してください。

// ... 省略 ...

// 拡張子を追加する
var path2 = path.appendingPathExtension("txt")
var path3 = path.appendingPathExtension(".txt")
var path4 = path.appendingPathExtension("")

// ... 省略 ...

Section 091

P.365, パス文字列のホームディレクトリ文字の置き換えを行う

「stringByExpandingTildeInPath」プロパティは「expandingTildeInPath」プロパティに置き換えられました。

var expandingTildeInPath: String { get }

サンプルコードは次のように変更してください。

import Foundation

// パス文字列を定義する
var path = NSString(string: "~/File.txt")

// ホームディレクトリパスの置き換えを行う
var path2 = path.expandingTildeInPath

// コンソールに出力する
print(path2)

Section 092

P.367, パス文字列の最後のコンポーネントを削除する

「stringByDeletingLastPathComponent」プロパティは「deletingLastPathComponent」プロパティに置き換えられました。

var deletingLastPathComponent: String { get }

サンプルコードは次のように変更してください。

// ... 省略 ...

// 最後のコンポーネントを削除する
var path3 = path.deletingLastPathComponent
var path4 = path2.deletingLastPathComponent

// ... 省略 ...

P.368, 同じディレクトリ内のファイルやディレクトリへのパスを作る

サンプルコードを次のように変更してください。

// ... 省略 ...

// ファイル名を「Image.jpg」に変えたファイルパスを作る
var path2 = path.deletingLastPathComponent
path2 = (path2 as NSString).appendingPathComponent("Image.jpg")

// ... 省略 ...

Section 093

P.369, パス文字列の拡張子を削除する

「stringByDeletingPathExtension」プロパティは「deletingPathExtension」プロパティに置き換えられました。

var deletingPathExtension: String { get }

サンプルコードは次のように変更してください。

// ... 省略 ...

// 拡張子を削除する
var path2 = path.deletingPathExtension

// ... 省略 ...

Section 093

P.370, 拡張子だけが異なるファイルパスを作成する

サンプルコードを次のように変更してください。

// ... 省略 ...

// 拡張子を「jpg」に変更したファイルパスを作る
var path2 = (path.deletingPathExtension as
    NSString).appendingPathExtension("jpg")

// ... 省略 ...

Section 094

P.371, パス文字列を正規化する

「stringByStandardizingPath」プロパティは「standardizingPath」に置き換えられました。

var standardizingPath: String { get }

サンプルコードは次のように変更してください。

// ... 省略 ...

// パス文字列を正規化する
var path2 = path.standardizingPath

// ... 省略 ...

Section 095

P.373, 文字列のURLエンコーディングを行う

「stringByAddingPercentEncodingWithAllowedCharacters」メソッドは「addingPercentEncoding」メソッドに置き換えられました。

func addingPercentEncoding(withAllowedCharacters allowedCharacters: CharacterSet) -> String?

サンプルコードは次のように変更してください。

// ... 省略 ...

// URLエンコーディングを行う
var str2 = str.addingPercentEncoding(
    withAllowedCharacters: CharacterSet.urlQueryAllowed)

// ... 省略 ...

P.374, URLエンコーディングされた文字列を元に戻すには

「stringByRemovingPercentEncoding」プロパティは「removingPercentEncoding」プロパティに置き換えられました。

var removingPercentEncoding: String? { get }

サンプルコードは次のように変更してください。

// ... 省略 ...

// URLエンコーディングをデコードする
var str2 = str.removingPercentEncoding

// ... 省略 ...

Section 096

P.379-380, 「Foundation」フレームワークのコレクションの複製について

「addObject」メソッドは「add」に置き換えられました。また、「NSMutableDictionary」の引数「forKey」に指定するオブジェクトは「NSCopying」プロトコルを実装していることを明示する必要があります。サンプルコードを次のように変更してください。

// ... 省略 ...

// 複製した配列とディクショナリに要素を追加する
newArray.add(4)
newDict.setObject("d", forKey: "4" as NSCopying)

// ... 省略 ...

Section 097

P.385, 空の配列の定義

型が定義されていない、空の配列は暗黙的に「NSArray」クラスとして扱われていましたが、コンパイルエラーになるようになりました。空の配列を定義するときは、型の指定が必要です。また、「first」を指定すると、「Collection」の「first」メソッドを取得できてしまうため、コンパイルエラーにはならなくなりました。しかし、取得できているのは関数オブジェクトであり、先頭のオブジェクトではない、ということには注意が必要です。

サンプルコードは次のように変更してください。

import Foundation

// 配列を定義する
// 空の配列のため、型を指定する必要がある
var strArray = NSArray(object: "TEST")

// Arrayの先頭のオブジェクトを取得するつもりで「first」を使っている
// しかし、「NSArray」クラスの「first」メソッドのオブジェクトを取得している
var str = strArray.first

// コンソールに出力する
print(str)

Section 100

P.390, 条件に合う要素のインデックス番号を取得するには

「indexesOfObjectsPassingTest」メソッドは「indexesOfObjects」メソッドに置き換えられました。

func indexOfObject(options opts: NSEnumerationOptions = [], passingTest predicate: (Any, Int, UnsafeMutablePointer<ObjCBool>) -> Bool) -> Int

サンプルコードは次のように変更してください。

// ... 省略 ...

// 偶数のインデックス番号を取得する
var idxes = (srcArray as NSArray).indexesOfObjects(options: []) {
    // ... 省略 ...
}

// ... 省略 ...

Section 101

P.392, 「append」メソッドと「appendContentsOf」メソッドについて

「appendContentsOf」メソッドは「append」メソッドに置き換えられました。

mutating func append(_ newElement: Element)

mutating func append<C : Collection where C.Iterator.Element == Element>(contentsOf newElements: C)

mutating func append<S : Sequence where S.Iterator.Element == Element>(contentsOf newElements: S)

サンプルコードは次のように変更してください。

// ... 省略 ...

// 配列の末尾に「10, 20, 30」を追加する
array.append(contentsOf: [10, 20, 30])

// ... 省略 ...

P.393, 配列の途中に挿入するには

「insert」メソッドの外部引数名が変更されています。

mutating func insert(_ newElement: Element, at i: Int)

サンプルコードは次のように変更してください。

// ... 省略 ...

// インデックス番号1の位置に「10」を挿入する
array.insert(10, at: 1)

// ... 省略 ...

SECTION 102

P.394, 配列から要素を削除する

「removeAtIndex」メソッドは「remove」メソッドに置き換えられました。

mutating func remove(at index: Int) -> Element

サンプルコードは次のように変更してください。

// ... 省略 ...

// インデックス番号2の要素を削除する
var ret = array.remove(at: 2)

// ... 省略 ...

P.394-395, 指定した範囲の要素を削除するには

「removeRange」メソッドは「removeSubrange」メソッドに置き換えられました。

public mutating func removeSubrange(_ bounds: CountableRange<Self.Index>)
// ... 省略 ...

// インデックス番号1から3までの範囲を削除する
array.removeSubrange(1 ..< 4)

// ... 省略 ...

P.395-396, 全要素を削除するには

「removeAll」メソッドの外部引数名が変更されました。

mutating func removeAll(keepingCapacity keepCapacity: Bool = default)

サンプルコードは次のように変更してください。

// ... 省略 ...

// 全要素を削除する
array.removeAll(keepingCapacity: false)

// ... 省略 ...

Section 103

P.397, 配列の要素を置き換える

「replaceRange」メソッドは「replaceSubrange」メソッドに置き換えられました。

mutating func replaceSubrange<C where C : Collection, C.Iterator.Element == _Buffer.Element>(_ subrange: Range<Int>, with newElements: C)

Section 104

P.398, 配列をソートする

「sortInPlace」メソッドは「sort」メソッドに置き換えられました。

mutating func sort(by areInIncreasingOrder: (Element, Element) -> Bool)

サンプルコードは次のように変更してください。

// ... 省略 ...

// ソートする
array.sort { (val1, val2) -> Bool in
    // 要素の比較処理。引数「val1」が引数「val2」よりも前になるかどうかを返す
    return val1 < val2
}

// ... 省略 ...

P.399, 配列を変更せずにソートされた配列を新規作成するには

「sort」メソッドは「sorted」メソッドに置き換えられました。

func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element]

サンプルコードは次のように変更してください。

// ... 省略 ...
// ソートした配列を作る
var newArray = array.sorted { (val1, val2) -> Bool in
    return val1 < val2
}
// ... 省略 ...

Section 105

P.400-401, 反転した配列を作る

「reverse」メソッドは「reversed」メソッドに置き換えられました。

func reversed() -> ReversedRandomAccessCollection<Array<Element>>

サンプルコードは次のように変更してください。

// ... 省略 ...

// コンソールに出力する
var str = ""
for i in array {
    str.append("\(i) ")
}
print(str)

// 反転した配列を作る
var newArray = array.reversed()

// コンソールに出力する
str = ""
for i in newArray {
    str.append("\(i) ")
}

// ... 省略 ...

Section 107

P.404, 配列の要素を検索する

「indexOf」メソッドは「index」メソッドに置き換えられました。

func index(of element: Element) -> Int?

サンプルコードは次のように変更してください。

// ... 省略 ...

// 「Forest」を検索する
var idx = array.index(of: "Forest")

// 「Hill」を検索する
var idx2 = array.index(of: "Hill")

// ... 省略 ...

P.405-406, 部分検索するには

「indexOf」メソッドは「index」メソッドに置き換えられました。

func index(of anObject: Any, in range: NSRange) -> Int

サンプルコードは次のように変更してください。

// ... 省略 ...

// 繰り返す
while true {
    // 「Book」を検索する
    var idx = array.index(of: "Book", in: range)
    // ... 省略 ...
}

SECTION 111

P.411, ディクショナリの要素を削除する

「removeValueForKey」メソッドは「removeValue」メソッドに置き換えられました。

mutating func removeValue(forKey key: Key) -> Value?

サンプルコードは次のように変更してください。

// ... 省略 ...

// キー「1st」の要素を削除する
dict.removeValue(forKey: "1st")

// ... 省略 ...

P.412, 全要素を削除するには

「removeAll」メソッドの引数の外部引数名が変更されています。

mutating func removeAll(keepingCapacity keepCapacity: Bool = default)

サンプルコードは次のように変更してください。

// ... 省略 ...

// 全要素を削除する
dict.removeAll(keepingCapacity: false)

// ... 省略 ...

SECTION 120

P.425, セットから条件に合う要素を取得する

「objectsPassingTest」メソッドは「objects」メソッドに置き換えられました。

func objects(options opts: NSEnumerationOptions = [], passingTest predicate: (Any, UnsafeMutablePointer<ObjCBool>) -> Bool) -> Set<AnyHashable>

サンプルコードは次のように変更してください。

// ... 省略 ...

// セットから奇数のみ取得する
var set2 = (set as NSSet).objects(options: []) { (obj, stop) -> Bool in
    // ... 省略 ...
}

// ... 省略 ...

SECTION 121

P.426, 2つのセットの両方に含まれる要素を取得する

「intersect」メソッドは「intersection」メソッド、「intersectInPlace」メソッドは「formIntersection」メソッドに置き換えられました。

func intersection(_ other: Set<Element>) -> Set<Element>

mutating func formIntersection<S : Sequence where S.Iterator.Element == Element>(_ other: S)

サンプルコードは次のように変更してください。

// ... 省略 ...

// 「set」と「set2」の両方に含まれる要素を残す
var set3 = set.intersection(set2)

// ... 省略 ...

P.427, 2つのセットの両方に含まれる要素があるかを判定するには

「intersectsSet」メソッドは「intersects」メソッドに置き換えられました。

func intersects(_ otherSet: Set<AnyHashable>) -> Bool

サンプルコードは次のように変更してください。

// ... 省略 ...

// 「set」と「set2」、「set」と「set3」とで両方に含まれる
// 要素があるかを調べる
var b1 = (set as NSSet).intersects(set2)
var b2 = (set as NSSet).intersects(set3)

// ... 省略 ...

SECTION 123

P.429, セットから別のセットに含まれる要素を削除する

「subtract」メソッドは「subtracting」メソッド、「subtractInPlace」メソッドは「subtract」メソッドに置き換えられました。

func subtracting(_ other: Set<Element>) -> Set<Element>

func subtracting<S : Sequence where S.Iterator.Element == Element>(_ other: S) -> Set<Element>

mutating func subtract<S : Sequence where S.Iterator.Element == Element>(_ other: S)

mutating func subtract(_ other: Set<Element>)

サンプルコードは次のように変更してください。

// ... 省略 ...

// 「set」から「set2」に含まれる要素を削除する
var set3 = set.subtracting(set2)

// ... 省略 ...

SECTION 124

P.431, 2つのセットのいずれかにしか含まれない要素を取得する

「exclusiveOr」メソッドは「symmetricDifference」メソッド、「exclusiveOrInPlace」メソッドは「formSymmetricDifference」メソッドに置き換えられました。

func symmetricDifference<S : Sequence where S.Iterator.Element == Element>(_ other: S) -> Set<Element>

mutating func formSymmetricDifference(_ other: Set<Element>)

mutating func formSymmetricDifference<S : Sequence where S.Iterator.Element == Element>(_ other: S)

サンプルコードは次のように変更してください。

// ... 省略 ...

// 「set」と「set2」のいずれかにしか含まれない要素を取得する
var set3 = set.symmetricDifference(set2)

// ... 省略 ...

SECTION 125

P.433, インデックスセットを作る

「NSIndexSet」クラスに対応するネイティブ型として「IndexSet」が追加されました。イニシャライザは以下の通りです。

init()
init(integer: Element)
init(integersIn range: Range<Element>)

サンプルコードは次のように変更してください。

import Foundation

// 空のインデックスセットを作る
var emptySet = IndexSet()

// インデックス番号を一つだけ持つインデックスセットを作る
var oneSet = IndexSet(integer: 3)

// 指定した範囲のインデックス番号を持つインデックスセットを作る
var rangeSet = IndexSet(integersIn: 3 ..< 8)

// ... 省略 ...

SECTION 125

P.434, 変更可能なインデックスセットを作るには

「IndexSet」は変更可能なインデックスセットです。「IndexSet」を使ってください。

SECTION 126

P.435, インデックスセットからインデックス番号を取得する

「firstIndex」プロパティは「first」プロパティ、「indexGreaterThanIndex」メソッドは「index」メソッドを使用します。

var first: Element? { get }
func integerGreaterThan(_ integer: Element) -> Element?

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var set = IndexSet(integersIn: 0 ..< 5)

// 先頭のインデックス番号を取得する
var i = set.first

// インデックス番号が見つからなくなるまでループする
while i != nil {
    // コンソールに出力する
    print(i)

    // 次に大きなインデックス番号を取得する
    i = set.integerGreaterThan(i!)
}

P.436, 降順にインデックス番号を取得するには

「lastIndex」プロパティは「last」プロパティ、「indexLessThanIndex」メソッドは「integerLessThan」メソッドを使用します。

var last: Element? { get }
func integerLessThan(_ integer: Element) -> Element?

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var set = IndexSet(integersIn: 0 ..< 5)

// 最後のインデックス番号を取得する
var i = set.last

// インデックス番号が見つからなくなるまでループする
while i != nil {
    // コンソールに出力する
    print(i)

    // 次に小さなインデックス番号を取得する
    i = set.integerLessThan(i!)
}

SECTION 127, インデックスセットにインデックス番号が含まれるかを調べる

「containsIndex」メソッドは「contains」メソッドに変更します。

func contains(_ integer: Element) -> Bool

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var set = IndexSet(integersIn: 0 ..< 5)

// 「3」がインデックスセットに含まれるかを調べる
var b1 = set.contains(3)

// 「6」がインデックスセットに含まれるかを調べる
var b2 = set.contains(6)

// コンソールに出力する
print("set.containsIndex(3) = \(b1)")
print("set.containsIndex(6) = \(b2)")

P.438, 指定した範囲のインデックス番号がインデックスセットに含まれるかを調べるには

「containsIndexesInRange」メソッドは「contains」メソッドに変更します。

func contains(integersIn range: Range<Element>) -> Bool

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var range = 0 ..< 5
var set = IndexSet(integersIn: range)

// 判定する範囲を定義
// インデックスセットに含まれる範囲
var range2 = 2 ..< 4

// インデックスセットに一部が含まれる範囲
var range3 = 4 ..< 7

// インデックスセットに含まれない範囲
var range4 = 6 ..< 8

// 各範囲を判定する
var b2 = set.contains(integersIn: range2)
var b3 = set.contains(integersIn: range3)
var b4 = set.contains(integersIn: range4)

// ... 省略 ...

P.439, 指定した範囲のインデックス番号がインデックスセットに一部でも含まれるかを調べるには

「intersectsIndexesInRange」メソッドは「intersects」メソッドに変更します。

func intersects(integersIn range: Range<Element>) -> Bool

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var range = 0 ..< 5
var set = IndexSet(integersIn: range)

// 判定する範囲を定義
// インデックスセットに含まれる範囲
var range2 = 2 ..< 4

// インデックスセットに一部が含まれる範囲
var range3 = 4 ..< 7

// インデックスセットに含まれない範囲
var range4 = 6 ..< 8

// 各範囲を判定する
var b2 = set.intersects(integersIn: range2)
var b3 = set.intersects(integersIn: range3)
var b4 = set.intersects(integersIn: range4)

// ... 省略 ...

P.440, 別のインデックスセットに格納されているインデックス番号が含まれるかを調べるには

「containsIndexes」メソッドは「contains」メソッドに変更します。

func contains(integersIn indexSet: IndexSet) -> Bool

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var range = 0 ..< 5
var set = IndexSet(integersIn: range)

// 判定するインデックスセットを定義
var set1 = IndexSet(integer: 2)

// 一部のみが含まれるインデックス番号を持つインデックスセット
range = 4 ..< 7
var set2 = IndexSet(integersIn: range)

// 含まれないインデックス番号を持つインデックスセット
var set3 = IndexSet(integer: 10)

// 各インデックスセットについて含まれるか判定する
var b1 = set.contains(integersIn: set1)
var b2 = set.contains(integersIn: set2)
var b3 = set.contains(integersIn: set3)

// ... 省略 ...

SECTION 128

P.441, インデックスセットからインデックス番号の個数を取得する

サンプルコードを次のように変更してください。

import Foundation

// インデックスセットを定義する
var range = 0 ..< 5
var set = IndexSet(integersIn: range)

// ... 省略 ...

P.442, 特定の範囲のインデックス番号の個数を取得する

「countOfIndexesInRange」メソッドは「count」メソッドに変更します。

func count(in range: Range<Element>) -> Int

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var range = 0 ..< 5
var set = IndexSet(integersIn: range)

// インデックス番号の個数を取得する
var n = set.count

// インデックス番号4から6までの範囲で個数を取得する
range = 4 ..< 7
var n2 = set.count(in: range)

// ... 省略 ...

SECTION 129

P.443, インデックスセットにインデックス番号を追加する

「addIndex」メソッドは「insert」メソッドに変更します。

mutating func insert(_ integer: Element) -> (inserted: Bool, memberAfterInsert: Element)

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var set = IndexSet()

// コンソールに出力する
print(set)

// インデックス番号を追加する
set.insert(2)
set.insert(4)

// コンソールに出力する
print(set)

P.444, 範囲を指定してインデックス番号を追加するには

「addIndexesInRange」メソッドは「insert」メソッドに変更します。

mutating func insert(integersIn range: Range<Element>)

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var set = IndexSet(integer: 5)

// コンソールに出力する
print(set)

// 範囲を指定してインデックス番号を追加する
set.insert(integersIn: 0 ..< 10)
set.insert(integersIn: 20 ..< 30)

// コンソールに出力する
print(set)

P.445, 他のインデックスセットに格納されているインデックス番号を追加するには

「addIndexes」メソッドは「formUnion」メソッドに変更します。

mutating func formUnion(_ other: IndexSet)

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var set = IndexSet()

// コンソールに出力する
print(set)

// 追加するインデックス番号を持ったインデックスセットを定義する
var set1 = IndexSet(integer: 2)
var set2 = IndexSet(integersIn: 5 ..< 10)

// インデックスセットを追加する
set.formUnion(set1)
set.formUnion(set2)

// コンソールに出力する
print(set)

SECTION 130

P.446, インデックスセットからインデックス番号を削除する

「removeIndex」メソッドは「remove」メソッドに変更します。

mutating func remove(_ integer: Element) -> Element?

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var range = 0 ..< 10
var set = IndexSet(integersIn: range)

// コンソールに出力する
print(set)

// インデックス番号を一つ削除する
set.remove(5)

// コンソールに出力する
print(set)

P.447, 範囲を指定してインデックス番号を削除するには

「removeIndexesInRange」メソッドは「remove」メソッドに置き換えられました。

mutating func remove(integersIn range: Range<Element>)

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var range = 0 ..< 10
var set = IndexSet(integersIn: range)

// コンソールに出力する
print(set)

// 範囲を指定して削除する
range = 2 ..< 9
set.remove(integersIn: range)

// コンソールに出力する
print(set)

P.448, 他のインデックスセットに格納されているインデックス番号を削除するには

「removeIndexes」メソッドは「remove」メソッドに置き換えられました。

mutating func subtract(_ other: IndexSet)

サンプルコードは次のように変更してください。

import Foundation

// インデックスセットを定義する
var range = 0 ..< 10
var set = IndexSet(integersIn: range)

// コンソールに出力する
print(set)

// 削除するインデックス番号を入れたインデックスセットを作る
var set1 = IndexSet()
set1.insert(1)
set1.insert(3)
set1.insert(5)

// インデックスセットから削除する
set.subtract(set1)

// コンソールに出力する
print(set)

P.449, インデックス番号をすべて削除するには

「removeAllIndexes」メソッドは「removeAll」メソッドに変更します。

mutating func removeAll()
import Foundation

// インデックスセットを定義する
var range = 0 ..< 10
var set = IndexSet(integersIn: range)

// コンソールに出力する
print(set)

// インデックス番号を全て削除する
set.removeAll()

// コンソールに出力する
print(set)

SECTION 131

P.452, トールフリーブリッジについて

「CFShow」にSwiftネイティブのオブジェクトを渡すときは、キャストが必要になりました。サンプルコードを次のように変更してください。

// ... 省略 ...

// 「CFShowStr」関数でコンソールに出力する
CFShow(str as CFString)
CFShow(nsstr)

SECTION 133

P.457-458, Objective-Cのクラスを呼ぶ

Objective-Cのメソッドの、Swift関数へのマッピングルールが変わりました。次のようにサンプルコードを変更してください。

main.swift

// ... 省略 ...

// 「calcAreaOfTriangleWithBase:height:」メソッドを呼ぶ
var area = calc.calcAreaOfTriangle(withBase:3, height: 4)

// ... 省略 ...

P.459-462, 「init」以外のイニシャライザメソッドを呼ぶには

Objective-Cのメソッドの、Swift関数へのマッピングルールが変わりました。次のようにサンプルコードを変更してください。

main.swift

// ... 省略 ...

// メソッドを呼ぶ
var ret1 = t1.reverseWords(in: baseStr)
var ret2 = t2?.reverseWords(in: baseStr)
var ret3 = t3?.reverseWords(in: baseStr)

// ... 省略 ...

P.462-463, クラスメソッドを呼ぶには

Objective-Cのメソッドの、Swift関数へのマッピングルールが変わりました。次のようにサンプルコードを変更してください。

main.swift

// ... 省略 ...

// メソッドを呼ぶ
var ret = StringTransform.reverseWords(in: baseStr)

// コンソールに出力する
print("ret = \(ret)")

SECTION 134

P.467-468, C言語の関数を呼ぶ

「alloc」メソッドと「initialize」メソッドは外部引数名が追加され、「dealloc」メソッドは「deallocate」メソッドに変更されました。サンプルコードを次のように変更してください。

main.swift

import Foundation

// C言語のポインタは「UnsafeMutablePointer」構造体にマッピングされる
// 10個分の「Int32」を入れられるバッファを確保
var values = UnsafeMutablePointer<Int32>.allocate(capacity: 10)

// バッファを初期化
values.initialize(to: 0)

// 値を埋める
for i in 0..<10 {
    values[i] = i + 1
}

// C言語の関数を使って計算する
var ret = calcSum(values, 10)

// バッファを解放する
values.deallocate(capacity: 10)

// コンソールに出力する
print("ret = \(ret)")

SECTION 135

P.476-478, Objective-CとSwiftでの名前空間について

Objective-Cのメソッドの、Swift関数へのマッピングルールが変わりました。次のようにサンプルコードを変更してください。

main.swift

import Foundation

// Objective-C側で出力する
print("*** FROM Objective-C ***")
let objCClass = MyObjCClass()
objCClass.printNames()

// ... 省略 ...

SECTION 139

P.488, ポインタを指定してデータを作成するには

「sizeof」を「MemoryLayout」を使ったコードに変更してください。次のようにサンプルコードを変更します。

// ... 省略 ...

// 各変数のポインタを取得してデータ化する
var intArrayData = NSData(bytes: intArray,
                          length: MemoryLayout<UInt16>.size * intArray.count)

var ptData = NSData(bytes: &pt,
                    length: MemoryLayout<Point3D>.size)

var intData = NSData(bytes: &i,
                     length: MemoryLayout<UInt32>.size)

// ... 省略 ...

SECTION 140

P.490-491, データのバッファにアクセスする

「unsafeBitCast」関数に外部引数名が追加されました。

func unsafeBitCast<T, U>(_ x: T, to: U.Type) -> U

サンプルコードは次のように変更してください。

// ... 省略 ...

// データの確保に成功しているか?
if data != nil {
    // 「Int32」が連続した領域としてバッファにアクセスする
    var p = unsafeBitCast(data!.mutableBytes,
        to: UnsafeMutablePointer<Int32>.self)

    // ... 省略 ...
}

// ... 省略 ...

P.491-492, 読み込み専用のデータの場合

「UnsafePointer」は「UnsafeRawPointer」に置き換えられました。

var bytes: UnsafeRawPointer { get }

サンプルコードは次のように変更してください。

import Foundation

// ポインタの内容をコンソールに出力する
func printPointer(_ pointer: UnsafeRawPointer, len: Int) {
    // 「UInt8」のポインタとして扱う
    let p = unsafeBitCast(pointer, to: UnsafePointer<UInt8>.self)

    // 16進数でバイトを文字列にする
    var str = ""
    for i in 0 ..< len {
        str.append(String(format: "%02X ", p[i]))
    }

    // コンソールに出力する
    print (str)
}

// 確保する容量を定義する
let bufSize = 20 // 4バイトの整数 * 5個

// データを確保する
var data = NSMutableData(length: bufSize)

// データの確保に成功しているか?
if data != nil {
    // 「Int32」が連続した領域としてバッファにアクセスする
    var p = unsafeBitCast(data!.mutableBytes,
        to: UnsafeMutablePointer<Int32>.self)

    // 1から5までの整数を埋める
    for i in 0..<5 {
        p[i] = i + 1
    }

    // コンソールに出力する
    printPointer(data!.bytes, len: bufSize)
}

SECTION 142

P.495, データを複製する

「sizeof」を「MemoryLayout」に変更してください。サンプルコードは次のように変更してください。

import Foundation

// 元のデータを作成する
var i: UInt32 = 0xABCD1234
var srcData = NSData(bytes: &i,
    length: MemoryLayout<UInt32>.size)

// 読み取り専用のデータとして複製する
var newData = NSData(data: srcData as Data)

// 変更可能なデータとして複製する
var newData2 = NSMutableData(data: srcData as Data)

// ... 省略 ...

P.496, バッファを複製するには

関数の引数の定義への「_ 」の追加、名称変更されたメソッドの置き換えなどを行ってください。サンプルコードを次のように変更してください。

import Foundation

// バッファを複製して読み込み専用のバッファを作る
func dupMutableBuffer(_ src: UnsafeMutableRawPointer, len: Int) ->
    UnsafeMutableRawPointer {

        // 新しいバッファを確保する
        let dst = malloc(len)

        if dst != nil {
            // バッファの内容をコピーする
            memcpy(dst, src, len)
        }

        return dst!
}

// バッファの内容をコンソールに出力する関数
func printBuffer(_ msg: String, p: UnsafePointer<UInt8>, len: Int) {
    print(msg)

    var str = ""
    for i in 0..<len {
        str.append(String(format: "%02X ", p[i]))
    }

    print(str)
}

// データを確保する
var data = NSMutableData(length: 5)

// データの確保に成功しているか?
if data != nil {
    // 「UInt8」のポインタを取得する
    var p = unsafeBitCast(data!.mutableBytes,
        to: UnsafeMutablePointer<UInt8>.self)

    // 1から5までの整数を埋める
    for i in 0..<5 {
        p[i] = UInt8(i + 1)
    }

    // データのバッファを複製して、変更可能なバッファを作る
    var readwrite = dupMutableBuffer(p, len: 5)

    // 作成したバッファの内容をコンソールに出力する
    p = unsafeBitCast(readwrite, to: UnsafeMutablePointer<UInt8>.self)
    printBuffer("readwrite", p: p, len: 5)

    // バッファを解放する
    free(readwrite)
}

P.497, 同じバッファを参照するデータを作成するには

「unsafeBitCast」関数の外部引数名を追加してください。サンプルコードは次のように変更してください。

import Foundation

// データを確保する
var srcData = NSMutableData(length: 5)!

// 内容を設定する
var p = unsafeBitCast(srcData.mutableBytes,
    to: UnsafeMutablePointer<UInt8>.self)

// ... 省略 ...

SECTION 143

P.499, データから一部分を取り出す

「subdataWithRange」メソッドは「subdata」メソッドに置き換えられました。

func subdata(with range: NSRange) -> Data

サンプルコードは次のように変更してください。

// ... 省略 ...

// データの一部分を取り出す
// ここでは、インデックス番号1を含めて3バイト取得する
var range = NSMakeRange(1, 3)
var subData = data.subdata(with: range)

// コンソールに出力する
print(subData as NSData)

SECTION 145

P.501, データを追加する

「appendBytes」メソッドは「append」メソッドに置き換えられました。

func append(_ bytes: UnsafeRawPointer, length: Int)

サンプルコードは次のように変更してください。

// ... 省略 ...

// データに追加する
// 「appendBytes」メソッドの引数は「UnsafePointer」構造体なので
// 配列を渡すこともできる
data.append(array, length: array.count)

// コンソールに出力する
print(data)

P.502-504, 追加回数が多いときは別の方法を検討する

関数の引数へ「_ 」の追加、メソッド名の変更などが必要です。サンプルコードを次のように変更してください。

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, to: UnsafeMutablePointer<UInt8>.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.append(bufPtr, length: bufLen)
        count += 1
        dataLen += bufLen
    }

    // 経過時間を計算する
    let dt = NSDate().timeIntervalSince(startDate as Date)

    // バッファを解放する
    free(buf)

    return (dt, count)
}

// 一括でデータを確保して、バッファに直接アクセスして設定する
func buildDataOnce(_ totalLength: Int) -> Double {
    // データを確保する
    let data = NSMutableData(length: totalLength)

    // ここから時間を計測する
    let startDate = NSDate()

    // バッファを取得する
    let p = unsafeBitCast(data!.mutableBytes,
        to: UnsafeMutablePointer<UInt8>.self)

    var value = 0

    for i in 0 ..< totalLength {
        p[i] = UInt8(value)
        value += 1

        if value > 255 {
            value = 0
        }
    }

    // 経過時間を計算する
    let dt = NSDate().timeIntervalSince(startDate as Date)

    return dt
}

// ... 省略 ...

P.505, 他のデータに格納されている内容を追加するには

「appendData」メソッドは「append」メソッドに置き換えられました。

func append(_ other: Data)

サンプルコードは次のように変更してください。

import Foundation

// 変更可能なデータを定義する
var i = UInt32(0x11223344)
var data = NSMutableData(bytes: &i,
    length: MemoryLayout<UInt32>.size)

// コンソールに出力する
print(data)

// 追加する内容を入れたデータを作る
var j = UInt32(0xAABBCCDD)
var intData = NSData(bytes: &j, length: 4)

// データを追加する
data.append(intData as Data)

// コンソールに出力する
print(data)

SECTION 146

P.506-507, データを置き換える

「replaceBytesInRange」メソッドは「replaceBytes」メソッドに置き換えられました。

func replaceBytes(in range: NSRange, withBytes bytes: UnsafeRawPointer)

func replaceBytes(in range: NSRange, withBytes replacementBytes: UnsafeRawPointer?, length replacementLength: Int)

サンプルコードは次のように変更してください。

// ... 省略 ...

// インデックス番号2から3バイトの範囲を「array2」の
// 内容に置き換える
var range = NSMakeRange(2, 3)
data.replaceBytes(in: range, withBytes: &array2, length: 2)

// コンソールに出力する
print(data)

P.507, データの途中に挿入するには

サンプルコードを次のように変更してください。

// ... 省略 ...

// インデックス番号2の位置に挿入する
var range = NSMakeRange(2, 0)
data.replaceBytes(in: range, withBytes: &array2, length: 2)

// コンソールに出力する
print(data)

P.508, データの一部分を削除するには

サンプルコードを次のように変更してください。

// ... 省略 ...

// インデックス番号3から2バイト削除する
var range = NSMakeRange(3, 2)
data.replaceBytes(in: range,
    withBytes: nil, length: 0)

// コンソールに出力する
print(data)

SECTION 147

P.509-510, データをファイルに書き出す

「writeToFile」メソッドは「write」メソッドに置き換えられました。

func write(toFile path: String, atomically useAuxiliaryFile: Bool) -> Bool

サンプルコードは次のように変更してください。

// ... 省略 ...

if let textData = text.data(
    using: String.Encoding.utf8, allowLossyConversion: false) {

        // デスクトップに書き出す
        var path = NSString(string:
            "~/Desktop/Test.txt").expandingTildeInPath
    var ret = (textData as NSData).write(toFile: path, atomically: true)

        // ... 省略 ...
}

SECTION 148

P.511-512, ファイルからデータを読み込む

サンプルコードを次のように変更してください。

import Foundation

// 読み込むファイルを作成する
func writeTestFile() -> String {

    // 書き出すデータを作る
    let bytes: [UInt8] = [0, 1, 2, 3, 4, 5]
    let data = NSData(bytes: bytes, length: bytes.count)

    // 書き出すファイルパス
    let path = NSString(string:
        "~/Desktop/Test.dat").expandingTildeInPath

    // ファイルに書き出す
    data.write(toFile: path, atomically: true)

    // ファイルパスを返す
    return path
}

// ... 省略 ...

SECTION 149

P.513, データをBase64でエンコードする

「base64EncodedStringWithOptions」メソッドは「base64EncodedString」メソッドに置き換えられました。

func base64EncodedString(options: NSData.Base64EncodingOptions = []) -> String

サンプルコードは次のように変更してください。

import Foundation

// 元のデータを作成する
var data = NSMutableData(length: 256)
var p = unsafeBitCast(data!.mutableBytes,
    to: UnsafeMutablePointer<UInt8>.self)

for i in 0 ..< 256 {
    p[i] = UInt8(i)
}

// BASE64でエンコードされた文字列を作る
// 64文字ごとに改行を入れる
var base64Str = data!.base64EncodedString(
    options: .lineLength64Characters)

// コンソールに出力する
print(base64Str)

P.514, エンコードするときのオプションについて

オプションの定数ですが、名称が変更されています。対応する定数は以下の通りです。

  • lineLength64Characters

  • lineLength76Characters

  • endLineWithCarriageReturn

  • endLineWithLineFeed

P.514-515, Base64でエンコードされたデータを作るには

「base64EncodedDataWithOptions」メソッドは「base64EncodedData」メソッドに置き換えられました。

func base64EncodedData(options: NSData.Base64EncodingOptions = []) -> Data

サンプルコードは次のように変更してください。

import Foundation

// 元のデータを作成する
var data = NSMutableData(length: 256)
var p = unsafeBitCast(data!.mutableBytes,
    to: UnsafeMutablePointer<UInt8>.self)

for i in 0 ..< 256 {
    p[i] = UInt8(i)
}

// BASE64でエンコードされたデータを作る
// 64文字ごとに改行を入れる
var base64Data = data!.base64EncodedData(
    options: .lineLength64Characters)

// 書き込むファイルパス
var path = NSString(string:
    "~/Desktop/Base64.txt").expandingTildeInPath

// 書き込む
(base64Data as NSData).write(toFile: path, atomically: true)

SECTION 150

P.516, Base64をデコードしたデータを作る

イニシャライザの定義が変更されました。

init?(base64Encoded base64String: String, options: NSData.Base64DecodingOptions = [])

サンプルコードは次のように変更してください。

import Foundation

// Base64でエンコードされた文字列
// ここでは「Swift」をUTF-8で出力したデータをエンコードしている
var base64Str = "U3dpZnQ="

// Base64をデコードする
if let data = NSData(base64Encoded: base64Str, options: []) {
    // 読み込んだデータから文字列を作る
    var str = String(data: data as Data, encoding: .utf8)

    // コンソールに出力する
    print(str!)
}

オプションの定数は以下のものに変更されています。

static var ignoreUnknownCharacters: NSData.Base64DecodingOptions { get }

P.517, Base64のデータをデコードするには

イニシャライザの定義が変更されました。

init?(base64Encoded base64Data: Data, options: NSData.Base64DecodingOptions = [])

サンプルコードは次のように変更してください。

import Foundation

// 読み込むファイルのファイルパス
var path = NSString(string:
    "~/Desktop/Base64.txt").expandingTildeInPath

// ファイルを読み込む
if let base64Data = NSData(contentsOfFile: path) {
    // Base64でデコードする
    var data = NSData(base64Encoded: base64Data as Data,
        options: .ignoreUnknownCharacters)

    // コンソールに出力する
    print(data!)
}

SECTION 151

P.518-519, JSONデータを作る

「NSJSONSerialization」は「JSONSerialization」に置き換えられました。また、「dataWithJSONObject」メソッドは「data」メソッドに置き換えられました。

class func data(withJSONObject obj: Any, options opt: JSONSerialization.WritingOptions = []) throws -> Data

オプションは次のように変更されています。

static var prettyPrinted: JSONSerialization.WritingOptions { get }

サンプルコードは次のように変更してください。

// ... 省略 ...

var topObj = [
    "String":str,
    "Integer":intValue,
    "Floating":floatingValue,
    "Array":array,
    "Dictionary":dict
] as [String: Any]

do {
    var jsonData = try JSONSerialization.data(withJSONObject:
        topObj, options: .prettyPrinted)

    // 文字列化する
    if let jsonStr = String(data: jsonData, encoding: .utf8) {
            // コンソールに出力する
            print(jsonStr)
    }
} catch let error as NSError {
    // JSONデータ化失敗時
    print("Failed")
}

P.519-520, JSON化できるか確認するには

サンプルコードを次のように変更してください。

// ... 省略 ...

var topObj = [
    "String":str,
    "Integer":intValue,
    "Floating":floatingValue,
    "Array":array,
    "Dictionary":dict
] as [String : Any]

// 各オブジェクトをトップオブジェクトにしたJSONが作れるか調べる
var topObjArray = [str, intValue, floatingValue,
    array, dict, topObj
] as [Any]

for obj in topObjArray {
    var type = type(of: obj)
    var b = JSONSerialization.isValidJSONObject(obj)
    print("isValidJSONObject(\(type)) = \(b)")
}

SECTION-152

P.521-522, JSONデータを読み込む

「JSONObjectWithData」メソッドは「jsonObject」メソッドに置き換えられました。

class func jsonObject(with data: Data, options opt: JSONSerialization.ReadingOptions = []) throws -> Any

サンプルコードは次のように変更してください。

import Foundation

// JSON文字列を定義する
var jsonStr = "{\"Integers\":[1, 2, 3, 4, 5]}"

// UTF-8のデータを作る
var jsonData = jsonStr.data(using: String.Encoding.utf8,
    allowLossyConversion: false)

do {
    // JSONをデコードする
    var obj = try JSONSerialization.jsonObject(with: jsonData!, options: [])

    // コンソールに出力する
    print(obj)
} catch let error as NSError {
    // デコード失敗
    print("Faield: \(error)")
}

P.522, 読み込みオプションについて

オプションは以下のように変更されました。

  • mutableContainers

  • mutableLeaves

  • allowFragments

SECTION 155

P.526-527, 指定した日時のオブジェクトを作成する

「NSCalendarIdentifierGregorian」は「gregorian」に置き換えられました。

static let gregorian: NSCalendar.Identifier

「dateFromComponents」メソッドは「date」メソッドに置き換えられました。

func date(from comps: DateComponents) -> Date?

サンプルコードは次のように変更してください。

import Foundation

// グレゴリオ暦用のカレンダーを取得する
var calendar = NSCalendar(
    calendarIdentifier: .gregorian)

// 取得する日時を定義する
// ここでは「2015年3月4日 13時52分16秒」を指定している
var comps = DateComponents()

// ... 省略 ...

// 日時を取得する
var date = calendar!.date(from: comps)

// コンソールに出力する
print(date)

P.527, 和暦を使用するには

「NSCalendarIdentifierJapanese」は「japanese」に置き換えられました。

static let japanese: NSCalendar.Identifier

サンプルコードは次のように変更してください。

import Foundation

// 和暦用のカレンダーを取得する
var calendar = NSCalendar(
    calendarIdentifier: .japanese)

// 取得する日時を定義する
// ここでは「平成27年1月1日0時0分0秒」を指定している
var comps = DateComponents()

// ... 省略 ...

// 日時を取得する
var date = calendar!.date(from: comps)

// コンソールに出力する
print(date)

P.528, ユーザーが設定したカレンダーを取得するには

「currentCalendar」メソッドは「current」プロパティ、「autoupdatingCurrentCalendar」メソッドは「autoupdatingCurrent」プロパティに置き換えられました。

class var current: Calendar { get }
class var autoupdatingCurrent: Calendar { get }

サンプルコードは次のように変更してください。

import Foundation

// システム設定のカレンダーを取得する
var calendar = NSCalendar.current

// 取得する日時を定義する
// ここでは「2015年1月1日0時0分0秒」を指定している
// 本書での実行環境はシステム設定は「西暦」になっている
var comps = DateComponents()

// ... 省略 ...

// 日時を取得する
var date = calendar.date(from: comps)

// コンソールに出力する
print(date)

SECTION 156

P.529-530, 指定した日時だけ経過した日時を取得する

「dateByAddingComponents」メソッドは「date」メソッドに置き換えられました。

func date(byAdding comps: DateComponents, to date: Date, options opts: NSCalendar.Options = []) -> Date?

サンプルコードは次のように変更してください。

import Foundation

// システム設定のカレンダーを取得する
var calendar = NSCalendar.current as NSCalendar

// 現在の日時を取得する
var now = Date()

// 34日後の日時を取得する
var comps = DateComponents()
comps.day = 34

var date1 = calendar.date(byAdding: comps,
    to: now , options: [])

// 13時間30分前の日時を取得する
comps = DateComponents()
comps.hour = -13
comps.minute = -30

var date2 = calendar.date(byAdding: comps,
    to: now, options: [])

// ... 省略 ...

P.530-531, 指定したコンポーネント以外に影響させないで日時を取得するには

「WrapComponents」は「wrapComponents」に置き換えられました。サンプルコードを次のように変更してください。

import Foundation

// システム設定のカレンダーを取得する
var calendar = NSCalendar.current as NSCalendar

// 現在の日時を取得する
var now = Date()

// 25時間後の日時を取得する
var comps = DateComponents()
comps.hour = 25

var date1 = calendar.date(byAdding: comps,
    to: now, options: [])

var date2 = calendar.date(byAdding: comps, to: now,
    options: .wrapComponents)

// ... 省略 ...

P.531, 指定した秒数だけ異なる日時を取得するには

「dateByAddingTimeInterval」メソッドは「addingTimeInterval」メソッドに置き換えられました。

func addingTimeInterval(_ timeInterval: TimeInterval) -> Date

サンプルコードは次のように変更してください。

import Foundation

// 現在の日時を取得する
var now = Date()

// 5秒後の日時を取得する
var date = now.addingTimeInterval(5)

// コンソールに出力する
print("now   = \(now)")
print("date  = \(date)")

SECTION 157

P.532, 日時の情報を取得する

「components」メソッドの定義が変わりました。

func components(_ unitFlags: NSCalendar.Unit, from date: Date) -> DateComponents

サンプルコードは次のように変更してください。

import Foundation

// 現在の日時を取得する
var now = Date()

// グレゴリオ暦(西暦)のカレンダーを取得する
var cal1 = NSCalendar(
    identifier: .gregorian)

// 和暦のカレンダーを取得する
var cal2 = NSCalendar(
    identifier: .japanese)

// 日時の情報を取得する
// グレゴリオ歴(西暦)のカレンダーから取得
var comps1 = cal1!.components(
    [.year, .month, .day, .hour, .minute, .second],
    from: now)

// 和暦のカレンダーから取得
var comps2 = cal2!.components(
    [.year, .month, .day, .hour, .minute, .second],
    from: now)

// ... 省略 ...

P.533-534, 引数「unitFlags」に指定可能な値について

以下の様に定義が変わっています。

static var era: NSCalendar.Unit { get }
static var year: NSCalendar.Unit { get }
static var month: NSCalendar.Unit { get }
static var day: NSCalendar.Unit { get }
static var hour: NSCalendar.Unit { get }
static var minute: NSCalendar.Unit { get }
static var second: NSCalendar.Unit { get }
static var weekday: NSCalendar.Unit { get }
static var weekdayOrdinal: NSCalendar.Unit { get }
static var quarter: NSCalendar.Unit { get } // 但し、非推奨
static var weekOfMonth: NSCalendar.Unit { get }
static var weekOfYear: NSCalendar.Unit { get }
static var yearForWeekOfYear: NSCalendar.Unit { get }
static var nanosecond: NSCalendar.Unit { get }
static var calendar: NSCalendar.Unit { get }
static var timeZone: NSCalendar.Unit { get }

P.534-535, 別のタイムゾーンでの日時を取得する

サンプルコードを次のように変更してください。

import Foundation

// 現在の日時を取得する
var now = Date()

// カレンダーを取得する
var cal = NSCalendar(
    calendarIdentifier: .gregorian)

// 日時の情報を取得する
var comps1 = cal!.components(
    [.year, .month, .day, .hour, .minute, .second, .timeZone],
    from: now)

// 協定世界時(UTC)での日時の情報を取得する
cal!.timeZone = TimeZone(secondsFromGMT: 0)!

var comps2 = cal!.components(
    [.year, .month, .day, .hour, .minute, .second, .timeZone],
    from: now)

// ... 省略 ...

SECTION 158

P.536-537, 日時を比較する

サンプルコードを次のように変更してください。

import Foundation

// 比較した結果を文字列で返す
func stringWithCompareResult(
    _ result: ComparisonResult) -> String {
        switch result {
        case .orderedSame:
            return "OrderedSame"

        case .orderedAscending:
            return "OrderedAscending"

        case .orderedDescending:
            return "OrderedDescending"
        }
}

// グレゴリオ暦(西暦)のカレンダーを取得する
var cal = NSCalendar(
    identifier: NSCalendar.Identifier.gregorian)

// 2015年1月1日0時0分0秒のオブジェクトを作る
var comps = DateComponents()

// ... 省略 ...

var baseDate = cal!.date(from: comps)

// 同じ日時、1日前、1日後のオブジェクトを作る
var date1 = cal!.date(from: comps)

comps = DateComponents()
comps.day = -1
var date2 = cal!.date(byAdding: comps,
    to: baseDate!, options: [])

comps = DateComponents()
comps.day = 1
var date3 = cal!.date(byAdding: comps,
    to: baseDate!, options: [])

// ... 省略 ...

P.538, 「compare」メソッド以外の比較メソッドについて

「isEqualToDate」メソッドは「isEqual」メソッドに置き換えられました。

func isEqual(to otherDate: Date) -> Bool

SECTION 159

P.539, 日時を文字列にする

「NSDateFormatter」クラスは「DateFormatter」に置き換えられました。「stringFromDate」メソッドは「string」メソッドに置き換えられました。

func string(from date: Date) -> String

サンプルコードは次のように変更してください。

import Foundation

// フォーマッタを作成
var formatter = DateFormatter()

// 日時ともに中くらいの情報量で文字列化する
formatter.dateStyle = .medium
formatter.timeStyle = .medium

// 現在日時を文字列化する
var str = formatter.string(from: Date())

// コンソールに出力する
print(str)

P.540, 「dateStyle」プロパティと「timeStyle」プロパティに指定可能な値について

以下の定数に変更されています。

  • none

  • short

  • medium

  • long

  • full

P.540-541, 使用するカレンダーを変更する

サンプルコードを以下の様に変更してください。

import Foundation

// フォーマッタを作成
var formatter = DateFormatter()

// 文字列化するスタイルを設定
formatter.dateStyle = .long
formatter.timeStyle = .medium

// 和暦のカレンダーを使用する
formatter.calendar = Calendar(
    identifier: .japanese)

// 現在日時を文字列化する
var str = formatter.string(from: Date())

// コンソールに出力する
print(str)

P.541, 使用するロケールを変更する

サンプルコードを以下の様に変更してください。

import Foundation

// フォーマッタを作成
var formatter = DateFormatter()

// 文字列化するスタイルを設定
formatter.dateStyle = .long
formatter.timeStyle = .medium

// ロケールを変更する
formatter.locale = Locale(identifier: "en_US")

// 現在日時を文字列化する
var str = formatter.string(from: Date())

// コンソールに出力する
print(str)

P.542, 使用するタイムゾーンを変更する

サンプルコードを以下の様に変更してください。

import Foundation

// フォーマッタを作成
var formatter = DateFormatter()

// 文字列化するスタイルを設定
formatter.dateStyle = .long
formatter.timeStyle = .long

// 現在日時を文字列化する
var now = Date()
var str = formatter.string(from: now)

// タイムゾーンを変更する
formatter.timeZone = TimeZone(secondsFromGMT: 0)

// 文字列化する
var str2 = formatter.string(from: now)

// コンソールに出力する
print(str)
print(str2)

P.543-544, 書式をカスタムで指定するには

サンプルコードを以下の様に変更してください。

import Foundation

// フォーマッタを作成
var formatter = DateFormatter()

// 書式を指定する
formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"

// 現在日時を文字列化する
let str = formatter.string(from: Date())

// コンソールに出力する
print(str)

SECTION 160

日時の差を計算する

「Date」の「timeIntervalSince」を使用するように変更します。

func timeIntervalSince(_ date: Date) -> TimeInterval

サンプルコードは以下の様に変更します。

import Foundation

// カレンダーを取得
var cal = Calendar(
    identifier: .gregorian)

// 2015年1月1日0時0分0秒の日時を取得する
var comps = DateComponents()
comps.year = 2015
comps.month = 1
comps.day = 1

var date = cal.date(from: comps)

// 1分後の日時を取得する
comps.minute = 1

var date2 = cal.date(from: comps)

// 「date2」と「date」の差を計算する
var dt = date2!.timeIntervalSince(date!)

// コンソールに出力する
print("dt = \(dt) sec")

P.546-547, 秒単位以外の単位で差を取得するには

「Calendar」の「components」メソッドを使用するように変更します。

func dateComponents(_ components: Set<Calendar.Component>, from start: Date, to end: Date) -> DateComponents

サンプルコードは以下の様に変更します。

import Foundation

// カレンダーを取得
var cal = Calendar(
    identifier: .gregorian)

// 2015年1月1日0時0分0秒の日時を取得する
var comps = DateComponents()
comps.year = 2015
comps.month = 1
comps.day = 1

var date = cal.date(from: comps)

// 532日後の日時を取得する
comps.day = 532

var date2 = cal.date(from: comps)

// 「date2」と「date」の差を計算する
comps = cal.dateComponents([.year, .month, .day],
    from: date!, to: date2!)

// コンソールに出力する
print("\(comps.year) years, \(comps.month) months and \(comps.day) days.")

P.547-548, 現在日時の差を計算するには

サンプルコードを以下の様に変更してください。

import Foundation

// カレンダーを取得
var cal = Calendar(
    identifier: .gregorian)

// 2015年1月1日0時0分0秒の日時を取得する
var comps = DateComponents()
comps.year = 2015
comps.month = 1
comps.day = 1

var date = cal.date(from: comps)

// 現在の日時との差を求める
var dt = date!.timeIntervalSinceNow

// ... 省略 ...

SECTION 161

ローカルタイムゾーンを取得する

「NSTimeZone」クラスも使用可能ですが、標準ライブラリのメソッドやプロパティは「TimeZone」に変更されているため、「TimeZone」を使用するように変更してください。ローカルタイムゾーンは「current」プロパティで取得します。

static var current: TimeZone { get }

サンプルコードは以下の様に変更してください。

import Foundation

// ローカルタイムゾーンを取得する
var tz = TimeZone.current

// コンソールに出力する
print(tz)

システムタイムゾーンを取得するには

システムタイムゾーンは「NSTimeZone」クラスの「system」プロパティで取得します。

class var system: TimeZone { get }

サンプルコードは以下の様に変更してください。

import Foundation

// ローカルタイムゾーンを取得する
var tz = TimeZone.current

// システムタイムゾーンを取得する
var sysTz = NSTimeZone.system

// ... 省略 ...

デフォルトタイムゾーン

デフォルトタイムゾーンは「NSTimeZone」クラスの「default」プロパティを使用します。

class var `default`: TimeZone { get set }

サンプルコードは以下の様に変更してください。

import Foundation

// ローカルタイムゾーンを取得する
var tz = TimeZone.current

// システムタイムゾーンを取得する
var sysTz = NSTimeZone.system

// デフォルトタイムゾーンを取得する
var defTz = NSTimeZone.default

// コンソールに出力する
print(tz)
print(sysTz)
print(defTz)

// デフォルトタイムゾーンを変更する
print("****** Change Default Time Zone *******")

var utc = TimeZone(secondsFromGMT: 0)
NSTimeZone.default = utc!

// ローカルタイムゾーンを取得する
tz = TimeZone.current

// システムタイムゾーンを取得する
sysTz = NSTimeZone.system

// デフォルトタイムゾーンを取得する
defTz = NSTimeZone.default

// コンソールに出力する
print(tz)
print(sysTz)
print(defTz)

SECTION 162

P.553-554, タイムゾーンの一覧を取得する

「knownTimeZoneNames」メソッドはプロパティに変わりました。

class var knownTimeZoneNames: [String] { get }

サンプルコードは以下の様に変更してください。

import Foundation

// タイムゾーンの一覧を取得する
var names = NSTimeZone.knownTimeZoneNames

// ... 省略 ...

SECTION 166

P.560, タイムゾーンの名前を取得する

「TimeZone」の「identifier」プロパティを使用するように変更します。

var identifier: String { get }

サンプルコードを以下の様に変更してください。

import Foundation

// ローカルタイムゾーンを取得する
var tz = TimeZone.current

// タイムゾーンの名前を取得する
var name = tz.identifier

// コンソールに出力する
print(name)

P.561, タイムゾーンの省略名を取得するには

「TimeZone」の「abbreviation」メソッドを使用するように変更します。

func abbreviation(for date: Date = default) -> String?

サンプルコードは以下の様に変更します。

import Foundation

// ローカルタイムゾーンを取得する
var tz = TimeZone.current

// タイムゾーンの省略名を取得する
let name = tz.abbreviation(for: Date())

// コンソールに出力する
print(name)

SECTION 167

P.562, カレントロケールを取得する

「NSLocale」も使用可能ですが、標準ライブラリのメソッドやプロパティは「Locale」に変更されているため、「Locale」を使用するように変更してください。カレントロケールは以下のプロパティで取得します。

static var autoupdatingCurrent: Locale { get }
static var current: Locale { get }

サンプルコードは以下の様に変更してください。

import Foundation

// 現在のロケールを取得する
var locale = Locale.autoupdatingCurrent

// ロケールの識別子を出力する
print(locale.identifier)

P.563, ロケール識別子について

「Locale」の「identifier」プロパティを使用するように変更します。

var identifier: String { get }

P.563, システムロケールを取得するには

「systemLocale」メソッドは「system」プロパティに置き換えられました。

class var system: Locale { get }

サンプルコードは以下の様に変更してください。

import Foundation

// システムのロケールを取得する
var locale = NSLocale.system

// ロケールの識別子を出力する
print("'\(locale.identifier)'")

SECTION 168

ロケールの情報を取得する

「objectForKey」メソッドは「object」メソッドに置き換えられました。

func object(forKey key: NSLocale.Key) -> Any?

但し、このメソッドは「NSLocale」クラスのメソッドです。使用するには、「NSLocale」へのキャストが必要です。「Locale」の場合は、各情報に対するプロパティが用意されています。

サンプルコードは以下の様に変更してください。

import Foundation

// カレントロケールを取得する
var locale = Locale.autoupdatingCurrent as NSLocale

// 取得する情報のキー配列を作る
var keys = [NSLocale.Key.identifier,
            NSLocale.Key.languageCode,
            NSLocale.Key.countryCode,
            NSLocale.Key.scriptCode,
            NSLocale.Key.variantCode,
            NSLocale.Key.exemplarCharacterSet,
            NSLocale.Key.calendar,
            NSLocale.Key.collationIdentifier,
            NSLocale.Key.usesMetricSystem,
            NSLocale.Key.measurementSystem,
            NSLocale.Key.decimalSeparator,
            NSLocale.Key.groupingSeparator,
            NSLocale.Key.currencySymbol,
            NSLocale.Key.currencyCode,
            NSLocale.Key.collatorIdentifier,
            NSLocale.Key.quotationBeginDelimiterKey,
            NSLocale.Key.quotationEndDelimiterKey,
            NSLocale.Key.alternateQuotationBeginDelimiterKey,
            NSLocale.Key.alternateQuotationEndDelimiterKey]

// 各情報を取得してコンソールに出力する
for key in keys {
    if let value = locale.object(forKey: key) {
        print("\(key) : \(value)")
    } else {
        print("\(key) : nil")
    }
}

P.565-566, 定義されているキーについて

サンプルコードで使用したキーに定義が変更されています。

P.566-567, 表示用文字列を取得する

「displayNameForKey」メソッドは「displayName」メソッドに置き換えられました。

func displayName(forKey key: NSLocale.Key, value: Any) -> String?

サンプルコードは以下の様に変更してください。

import Foundation

// カレントロケールを取得する
var locale = Locale.autoupdatingCurrent as NSLocale

// 取得する情報のキー配列を作る
var keys = [NSLocale.Key.identifier,
            NSLocale.Key.languageCode,
            NSLocale.Key.countryCode,
            NSLocale.Key.scriptCode,
            NSLocale.Key.variantCode,
            NSLocale.Key.exemplarCharacterSet,
            NSLocale.Key.calendar,
            NSLocale.Key.collationIdentifier,
            NSLocale.Key.usesMetricSystem,
            NSLocale.Key.measurementSystem,
            NSLocale.Key.decimalSeparator,
            NSLocale.Key.groupingSeparator,
            NSLocale.Key.currencySymbol,
            NSLocale.Key.currencyCode,
            NSLocale.Key.collatorIdentifier,
            NSLocale.Key.quotationBeginDelimiterKey,
            NSLocale.Key.quotationEndDelimiterKey,
            NSLocale.Key.alternateQuotationBeginDelimiterKey,
            NSLocale.Key.alternateQuotationEndDelimiterKey]

// 各情報を取得してコンソールに出力する
for key in keys {
    // 文字列の値を取得する
    if let value = locale.object(forKey: key) as? String {
        // 表示用文字列を取得する
        if let str = locale.displayName(forKey: key, value: value) {
            print("\(key) : \(value) -> \(str)")
        }
    }
}

SECTION 169

P.568-569, ISO言語コードの一覧を取得する

「ISOLanguageCodes」メソッドは「isoLanguageCodes」プロパティに置き換えられました。

class var isoLanguageCodes: [String] { get }

サンプルコードは以下の様に変更してください。

import Foundation

// ISO言語コードの一覧を取得する
var langs = NSLocale.isoLanguageCodes

// ... 省略 ...

SECTION 170

P.570-571, ISO国コードの一覧を取得する

「ISOCountryCodes」メソッドは「isoCountryCodes」プロパティに置き換えられました。

class var isoCurrencyCodes: [String] { get }

サンプルコードは以下の様に変更してください。

import Foundation

// ISO国コードの一覧を取得する
var codes = NSLocale.isoCountryCodes

// ... 省略 ...

SECTION 171

P.572-573, ISO通貨コードの一覧を取得する

「ISOCurrencyCodes」メソッドは「isoCurrencyCodes」プロパティに置き換えられました。

class var isoCurrencyCodes: [String] { get }

サンプルコードは以下の様に変更してください。

import Foundation

// ISO通貨コードの一覧を取得する
var codes = NSLocale.isoCurrencyCodes

// ... 省略 ...

P.574, ISO共通通貨コードの一覧を取得する

「commonISOCurrencyCodes」メソッドは「commonISOCurrencyCodes」プロパティに置き換えられました。

class var commonISOCurrencyCodes: [String] { get }

サンプルコードは以下の様に変更してください。

import Foundation

// ISO共通通貨コードの一覧を取得する
var codes = NSLocale.commonISOCurrencyCodes

// ... 省略 ...

SECTION 172

P.575-576, ロケール識別子の一覧を取得する

「availableLocaleIdentifiers」メソッドはプロパティに変わりました。

class var availableLocaleIdentifiers: [String] { get }

サンプルコードは以下の様に変更してください。

import Foundation

// ロケール識別子の一覧を取得する
var identifiers = NSLocale.availableLocaleIdentifiers

// ... 省略 ...

SECTION 173

P.577, 指定した識別子のロケールを取得する

サンプルコードを以下の様に変更してください。

// ... 省略 ...
if let currency =
    locale.object(forKey: NSLocale.Key.currencyCode) as? String {
        print(currency)
}

if let currency =
    locale2.object(forKey: NSLocale.Key.currencyCode) as? String {
        print(currency)
}

SECTION 177

P.585, 相対URLを作成する

イニシャライザの定義が変わりました。

init?(string URLString: String, relativeTo baseURL: URL?)

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// ベースURLから相対URLを作成する
var url = NSURL(string: "blog", relativeTo: baseUrl as? URL)

// ... 省略 ...

SECTION 178

P.586, 相対URLから絶対URLを取得する

サンプルコードを以下の様に変更してください。

// ... 省略 ...

// ベースURLから相対URLを作成する
var relativeUrl = NSURL(string: "blog", relativeTo: baseUrl as? URL)

// ... 省略 ...

SECTION 183

P.594, URLのパスにコンポーネントを追加する

「URLByAppendingPathComponent」メソッドは「appendingPathComponent」メソッドに置き換えられました。

func appendingPathComponent(_ pathComponent: String) -> URL?

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// パスコンポーネントを追加したURLを作る
var url2 = url.appendingPathComponent("Sample.txt")

// コンソールに出力する
print(url2)

P.595, 追加するコンポーネントがディレクトリかどうかを指定するには

「URLByAppendingPathComponent」メソッドは「appendingPathComponent」メソッドに置き換えられました。

func appendingPathComponent(_ pathComponent: String, isDirectory: Bool) -> URL?

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// パスコンポーネントを追加したURLを作る
var fileUrl = url.appendingPathComponent("Sample",
    isDirectory: false)
var dirUrl = url.appendingPathComponent("Sample",
    isDirectory: true)

// ... 省略 ...

SECTION 184

P.596, URLのパスから最後のコンポーネントを削除する

「URLByDeletingLastPathComponent」プロパティは「deletingLastPathComponent」プロパティに置き換えられました。

var deletingLastPathComponent: URL? { get }

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// 最後のコンポーネントを削除する
var url1 = (fileUrl! as NSURL).deletingLastPathComponent
var url2 = (dirUrl! as NSURL).deletingLastPathComponent

// ... 省略 ...

SECTION 185

P.598-599, URLのパスに拡張子を追加する

「URLByAppendingPathExtension」メソッドは「appendingPathExtension」メソッドに置き換えられました。

func appendingPathExtension(_ pathExtension: String) -> URL?

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// 拡張子を追加する
var url1 = (fileUrl! as NSURL).appendingPathExtension("txt")
var url2 = (dirUrl! as NSURL).appendingPathExtension("txt")

// ... 省略 ...

SECTION 186

P.600-601, URLのパスから拡張子を削除する

「URLByDeletingPathExtension」プロパティは「deletingPathExtension」プロパティに置き換えられました。

var deletingPathExtension: URL? { get }

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// 拡張子を削除したURLを作成する
var fileUrl2 = fileUrl.deletingPathExtension
var noExtUrl2 = noExtUrl.deletingPathExtension
var dirUrl2 = dirUrl.deletingPathExtension

// ... 省略 ...

SECTION 187

P.602-603, URLのパスを正規化するには「URLByStandardizingPath」プロパティを使う

「URLByStandardizingPath」プロパティは「standardizingPath」プロパティに置き換えられました。

var standardizingPath: URL? { get }

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// 相対URLを作成する
var relUrl = NSURL(string: "Test2/../Sample2.txt",
    relativeTo: absUrl as URL)

// URLを正規化する
var absUrl2 = absUrl.standardizingPath
var relUrl2 = relUrl!.standardizingPath

// ... 省略 ...

SECTION 188

P.604-605, ファイルを部分的に書き込む

「NSFileHandle」は「FileHandle」、「NSFileManager」は「FileManager」に置き換えられました。URLを引数に取るイニシャライザの定義が変わっています。

convenience init(forWritingTo url: URL) throws

サンプルコードは以下の様に変更してください。

import Foundation

// 書き込み先のファイルパス
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// 書き込み先にファイルが存在したら削除する
var fm = FileManager()

if fm.fileExists(atPath: path) {
    do {
        try fm.removeItem(atPath: path)
    } catch let error as NSError {

    }
}

// 空のファイルを作成する
fm.createFile(atPath: path, contents: nil, attributes: nil)

// 書き込み用のファイルハンドルを取得する
var fh = FileHandle(forWritingAtPath: path)

if fh != nil {
    // 「Swift」と書き込む
    var data = NSData(bytes: "Swift", length: 5)
    fh!.write(data as Data)

    // 「 and Objective-C」と書き込む
    data = NSData(bytes: " and Objective-C", length: 16)
    fh!.write(data as Data)

    // ファイルを閉じる
    fh!.closeFile()
}

P.605-606, ファイルを更新モードで開くには

URLを引数に取るイニシャライザの定義が変わっています。

convenience init(forUpdating url: URL) throws

サンプルコードは以下の様に変更してください。

import Foundation

// 書き込み先のファイルパス
var path = NSString(string: "~/Test.dat").expandingTildeInPath

// 書き込み先にファイルが存在したら削除する
var fm = FileManager()

if fm.fileExists(atPath: path) {
    do {
        try fm.removeItem(atPath: path)
    } catch let error as NSError {

    }
}

// 空のファイルを作成する
fm.createFile(atPath: path, contents: nil, attributes: nil)

// 書き込み用のファイルハンドルを取得する
var fh = FileHandle(forUpdatingAtPath: path)

if fh != nil {
    // 1, 2, 3, 4, 5を書き込む
    var array: [UInt8] = [1, 2, 3, 4, 5]
    fh!.write(Data(bytes: &array, count: array.count))

    // ファイルポインタを先頭に移動する
    fh!.seek(toFileOffset: 0)

    // 書き込み済みの内容を読み込む
    var data = fh!.readDataToEndOfFile()

    // コンソールに出力する
    print(data)

    // 6, 7, 8, 9, 10を書き込む
    array = [6, 7, 8, 9, 10]
    fh!.write(Data(bytes: &array, count: array.count))

    // ファイルポインタを先頭に移動する
    fh!.seek(toFileOffset: 0)

    // 書き込み済みの内容を読み込む
    data = fh!.readDataToEndOfFile()

    // コンソールに出力する
    print(data)

    // ファイルを閉じる
    fh!.closeFile()
}

SECTION 189

P.608-609, ファイルを部分的に読み込む

「readDataOfLength」メソッドは「readData」メソッドに置き換えられました。

func readData(ofLength length: Int) -> Data

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルパス
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// 部分的に読み込むテストファイルを作成する
var str = "Swift"
do {
    try str.write(toFile: path, atomically: true,
        encoding: .utf8)
} catch let error as NSError {

}

// 読み込み用のファイルハンドルを取得する
var fh = FileHandle(forReadingAtPath: path)

if fh != nil {

    // 1バイトずつ読み込み、コンソールに出力する
    var reading = true
    while reading {

        // 1バイト読み込む
        var data = fh!.readData(ofLength: 1) as NSData
        if data.length > 0 {
            // 読み込んだバイトを文字としてコンソールに出力
            var p = unsafeBitCast(data.bytes,
                                  to: UnsafePointer<CChar>.self)
            var c = String(format:"%c", p[0])
            print(c)
        } else {
            // 最後まで読み込み済み
            reading = false
        }
    }

    // ファイルを閉じる
    fh!.closeFile()
}

P.609, ファイルを読み込みモードで開くには

URLを指定するイニシャライザの定義が変わりました。

convenience init(forReadingFrom url: URL) throws

P.609-610, ファイルを最後まで読み込むには

サンプルコードを以下の様に変更してください。

import Foundation

// ファイルパス
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// 部分的に読み込むテストファイルを作成する
var str = "Swift"
do {
    try str.write(toFile: path, atomically: true,
        encoding: .utf8)
} catch let error as NSError {

}

// 読み込み用のファイルハンドルを取得する
var fh = FileHandle(forReadingAtPath: path)

if fh != nil {

    // ファイルの末尾まで一気に読み込み、変更可能なデータにする
    var data = NSMutableData(data: fh!.readDataToEndOfFile())

    // 読み込んだデータを文字列として読み込む
    var text = String(bytesNoCopy: data.mutableBytes,
        length: data.length, encoding:.utf8,
        freeWhenDone:false)

    // コンソールに出力する
    print(text)

    // ファイルを閉じる
    fh!.closeFile()
}

SECTION 190

P.611-612, ファイルを任意の位置で読み書きする

「seekToFileOffset」メソッドは「seek」メソッドに置き換えられました。

func seek(toFileOffset offset: UInt64)

サンプルコードは以下の様に変更してください。

import Foundation

// テキストデータをコンソールに出力する関数
func printTextData(data: Data) {

    // 文字列を作成する
    let str = String(data: data, encoding: .utf8)

    // コンソールに出力する
    print(str)
}

// ファイルパス
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// 部分的に読み込むテストファイルを作成する
var str = "Swift Objective-C"
do {
    try str.write(toFile: path, atomically: true,
        encoding: .utf8)
} catch let error as NSError {

}

// 読み込み用のファイルハンドルを取得する
var fh = FileHandle(forReadingAtPath: path)

if fh != nil {

    // 先頭から6バイトの場所から、末尾まで読み込む
    fh!.seek(toFileOffset: 6)
    var data = fh!.readDataToEndOfFile()

    // コンソールに出力
    printTextData(data: data)

    // 先頭に移動して、5バイト読み込む
    fh!.seek(toFileOffset: 0)
    data = fh!.readData(ofLength: 5)

    // コンソールに出力
    printTextData(data: data)

    // ファイルを閉じる
    fh!.closeFile()
}

P.612-613, ファイルポインタの現在位置を取得するには

サンプルコードを以下の様に変更してください。

import Foundation

// テキストデータをコンソールに出力する関数
func printTextData(data: Data) {

    // 文字列を作成する
    let str = String(data: data, encoding: .utf8)

    // コンソールに出力する
    print(str)
}

// ファイルパス
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// 部分的に読み込むテストファイルを作成する
var str = "Swift Objective-C"
do {
    try str.write(toFile: path, atomically: true,
        encoding: .utf8)
} catch let error as NSError {

}

// 読み込み用のファイルハンドルを取得する
var fh = FileHandle(forReadingAtPath: path)

if fh != nil {

    // 先頭から6バイトの場所から、末尾まで読み込む
    fh!.seek(toFileOffset: 6)

    // ファイルポインタの位置を出力
    print("before: \(fh!.offsetInFile)")
    var data = fh!.readDataToEndOfFile()
    print("after: \(fh!.offsetInFile)")

    // コンソールに出力
    printTextData(data: data)

    // 先頭に移動して、5バイト読み込む
    fh!.seek(toFileOffset: 0)
    print("before: \(fh!.offsetInFile)")
    data = fh!.readData(ofLength: 5)
    print("after: \(fh!.offsetInFile)")

    // コンソールに出力
    printTextData(data: data)

    // ファイルを閉じる
    fh!.closeFile()
}

P.614-615, ファイルの末尾にファイルポインタを移動するには

サンプルコードを以下の様に変更してください。

import Foundation

// ファイルパス
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// テストファイルを作成する
var str = "Swift"
do {
    try str.write(toFile: path, atomically: true,
        encoding: .utf8)
} catch let error as NSError {

}


// ファイルハンドルを取得する
var fh = FileHandle(forWritingAtPath: path)

if fh != nil {

    // ファイルポインタを末尾に移動する
    fh!.seekToEndOfFile()

    // 「 Objective-C」を追記する
    str = " Objective-C"

    var data = str.data(using: .utf8,
        allowLossyConversion: false)

    if data != nil {
        fh!.write(data!)
    }

    // ファイルを閉じる
    fh!.closeFile()
}

// ファイルを読み込む
do {
    let text = try String(contentsOfFile: path,
        encoding: .utf8)

    // コンソールに出力する
    print(text)
} catch let error as NSError {

}

SECTION 191

P.616-617, ファイルポインタ以降を切り捨てる

「truncateFileAtOffset」メソッドは「truncateFile」メソッドに置き換えられました。

func truncateFile(atOffset offset: UInt64)

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルパス
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// テストファイルを作成する
var str = "Swift and Objective-C"
do {
    try str.write(toFile: path, atomically: true,
        encoding: .utf8)
} catch let error as NSError {

}

// ファイルハンドルを取得する
var fh = FileHandle(forWritingAtPath: path)

if fh != nil {

    // 5バイト目以降を切り捨てる
    fh!.truncateFile(atOffset: 5)

    // ファイルを閉じる
    fh!.closeFile()
}

// ファイルを読み込む
do {
    let text = try String(contentsOfFile: path,
        encoding: .utf8)

    // コンソールに出力する
    print(text)
} catch let error as NSError {

}

SECTION 192

P.618, バンドルを取得する

「NSBundle」は「Bundle」に置き換えられました。

class var main: Bundle { get }

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // コンソールに出力する
        print(bundle)
    }

}

P.619, バンドルパスを指定してバンドルを取得するには

サンプルコードを以下の様に変更してください。

// ... 省略 ...

// バンドルを取得する
var bundle = Bundle(path: path)

// ... 省略 ...

// バンドルの取得を試みる
var bundle2 = Bundle(path: path)

// ... 省略 ...

P.620, URLを指定してバンドルを取得するには

イニシャライザの定義が変わっています。

convenience init?(url: URL)

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// URLを取得する
var url = URL(fileURLWithPath: path)

// バンドルを取得する
var bundle = Bundle(url: url)

// ... 省略 ...

// URLを取得する
url = URL(fileURLWithPath: path)

// バンドルの取得を試みる
var bundle2 = Bundle(url: url)

// ... 省略 ...

P.621, クラスを指定してバンドルを取得するには

イニシャライザの定義が変更されています。

init(for aClass: AnyClass)

サンプルコードは以下の様に変更してください。

import Foundation

// 「NSString」クラスを実装しているバンドルを取得する
if let strClass = NSClassFromString("NSString") {
    // バンドルを取得する
    var bundle = Bundle(for: strClass)

    // コンソールに出力する
    print(bundle)
}

P.622, 識別子を指定してバンドルを取得するには

サンプルコードを以下の様に変更してください。

// ... 省略 ...

// バンドルを取得する
var bundle = Bundle(identifier: identifier)

// 取得できないバンドル識別子を定義
identifier = "private.test.framework"

// バンドルの取得を試みる
var bundle2 = Bundle(identifier: identifier)

// ... 省略 ...

SECTION 193

P.623-624, バンドルへのディレクトリパスを取得する

サンプルコードを以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // ... 省略 ...
    }

}

SECTION 194

P.626-627, バンドル内のリソースファイルを取得する

「pathForResource」メソッドは「path」メソッドに置き換えられました。

func path(forResource name: String?, ofType ext: String?) -> String?

func path(forResource name: String?, ofType ext: String?, inDirectory subpath: String?) -> String?

func path(forResource name: String?, ofType ext: String?, inDirectory subpath: String?, forLocalization localizationName: String?) -> String?

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // リソースとして組み込んだ「Test.txt」ファイルのパスを取得する
        let filePath = bundle.path(forResource: "Test", ofType: "txt")

        // コンソールに出力する
        print(filePath)
    }

}

P.627-628 リソースファイルのURLを取得するには

「URLForResource」メソッドは「url」メソッドに置き換えられました。

func url(forResource name: String?, withExtension ext: String?) -> URL?

func url(forResource name: String?, withExtension ext: String?, subdirectory subpath: String?) -> URL?

func url(forResource name: String?, withExtension ext: String?, subdirectory subpath: String?, localization localizationName: String?) -> URL?

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // リソースとして組み込んだ「Test.txt」ファイルのURLを取得する
        let url = bundle.url(forResource: "Test", withExtension: "txt")

        // コンソールに出力する
        print(url)
    }

}

P.629-630, 拡張子を指定してリソースファイルの配列を取得するには

「pathsForResourcesOfType」メソッドは「paths」メソッド、「URLsForResourcesWithExtension」メソッドは「urls」メソッドに置き換えられました。

func paths(forResourcesOfType ext: String?, inDirectory subpath: String?) -> [String]

func paths(forResourcesOfType ext: String?, inDirectory subpath: String?, forLocalization localizationName: String?) -> [String]

func urls(forResourcesWithExtension ext: String?, subdirectory subpath: String?) -> [URL]?

func urls(forResourcesWithExtension ext: String?, subdirectory subpath: String?, localization localizationName: String?) -> [URL]?

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // 拡張子が「txt」のリソースファイルのパスの配列を取得する
        let paths = bundle.paths(forResourcesOfType: "txt", inDirectory: nil)

        // 拡張子が「txt」のリソースファイルのURLの配列を取得する
        let urls = bundle.urls(forResourcesWithExtension: "txt", subdirectory: nil)

        // ... 省略 ...
    }

}

SECTION 195

P.631, バンドル識別子を取得する

サンプルコードを以下の様に変更してください。

// ... 省略 ...

// バンドルを取得する
if let bundle = Bundle(path: path) {
    // ... 省略 ...
}

SECTION 196

P.632, バンドルの情報ディクショナリを取得する

サンプルコードを以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // ... 省略 ...
    }

}

P.633-634, 情報ディクショナリの値を取得する

「objectForInfoDictionaryKey」メソッドは「object」メソッドに置き換えられました。

func object(forInfoDictionaryKey key: String) -> Any?

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // ... 省略 ...

        // メソッドを使って取得する
        let name = bundle.object(forInfoDictionaryKey: "CFBundleName")
        let vers = bundle.object(forInfoDictionaryKey: "CFBundleVersion")

        // ... 省略 ...
    }

}

P.634-636, ローカライズされた情報ディクショナリを取得するには

サンプルコードを以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // ... 省略 ...
    }

}

SECTION 197

P.637-638, ローカライズ文字列を取得する

「localizedStringForKey」メソッドは「localizedString」メソッドに置き換えられました。

func localizedString(forKey key: String, value: String?, table tableName: String?) -> String

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // 文字列を取得する
        let message = bundle.localizedString(forKey: "Message",
            value: nil, table: nil)
        let test = bundle.localizedString(forKey: "Test",
            value: nil, table: nil)

        // 「Localizble.strings」ファイルに入っていない文字列の
        // 取得を試みる
        let unknown = bundle.localizedString(forKey: "Unknown",
            value: nil, table: nil)

        // ... 省略 ...
    }

}

SECTION 198

P.639, バンドルが持つローカライズ言語を取得する

サンプルコードを以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // ... 省略 ...
    }

}

P.640, 使用するべき言語を取得する

サンプルコードを以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動処理完了直後の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // メインバンドル(ここではアプリ本体)を取得する
        let bundle = Bundle.main

        // ... 省略 ...
    }

}

SECTION 199

P.641-642, 指定したディレクトリ内のファイルやサブディレクトリを取得する

「contentsOfDirectoryAtPath」メソッドは「contentsOfDirectory」メソッドに置き換えられました。

func contentsOfDirectory(atPath path: String) throws -> [String]

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// ディレクトリの内容を取得する
do {
    let dirContents = try fm.contentsOfDirectory(atPath: path)
    // ... 省略 ...
} catch let error as NSError {

}

P.642-643, URLで指定したディレクトリ内の項目を取得するには

「contentsOfDirectoryAtURL」メソッドは「contentsOfDirectory」メソッドに置き換えられました。

func contentsOfDirectory(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = []) throws -> [URL]

オプションは以下の様に変更されています。

  • skipsSubdirectoryDescendants

  • skipsPackageDescendants

  • skipsHiddenFiles

サンプルコードは以下の様に変更してください。

import Foundation

// 内容を取得するディレクトリのパス
var path = "/System/Library"

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// URLを作成する
let url = URL(fileURLWithPath: path)

do {
    // ディレクトリの内容を取得する
    let dirContents = try fm.contentsOfDirectory(at: url,
        includingPropertiesForKeys: nil,
        options: .skipsSubdirectoryDescendants)

    // コンソールに出力する
    print(dirContents)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.644-645, 順次アクセスしてディレクトリ内の項目を取得するには

「enumeratorAtPath」メソッドと「enumeratorAtURL」メソッドは「enumerator」メソッドに置き換えられました。

func enumerator(atPath path: String) -> FileManager.DirectoryEnumerator?

func enumerator(at url: URL, includingPropertiesForKeys keys: [URLResourceKey]?, options mask: FileManager.DirectoryEnumerationOptions = [], errorHandler handler: (@escaping (URL, Error) -> Bool)? = nil) -> FileManager.DirectoryEnumerator?

サンプルコードは以下の様に変更してください。

import Foundation

// 内容を取得するディレクトリのパス
var path = "/System/Library"

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// ディレクトリの内容を順次アクセスする
if let enumerator = fm.enumerator(atPath: path) {

    // 内容を取得する
    while let subPath = enumerator.nextObject() as? String {

        // ファイルタイプを取得する
        if let type = enumerator.fileAttributes![FileAttributeKey.type]
            as? FileAttributeType {
                if type == FileAttributeType.typeDirectory {
                    print("\(subPath)\t[DIR]")
                } else {
                    print(subPath)
                }
        }
        // サブディレクトリはスキップする
        enumerator.skipDescendants()
    }
}

SECTION 200

P.646-647, ボリュームの一覧を取得する

「mountedVolumeURLsIncludingResourceValuesForKeys」メソッドは「mountedVolumeURLs」メソッドに置き換えられました。

func mountedVolumeURLs(includingResourceValuesForKeys propertyKeys: [URLResourceKey]?, options: FileManager.VolumeEnumerationOptions = []) -> [URL]?

オプションは以下の様に先頭の文字が小文字に変更されています。

  • skipHiddenVolumes

  • produceFileReferenceURLs

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// マウントされているボリュームのURLの配列を取得する
var array =
fm.mountedVolumeURLs(
    includingResourceValuesForKeys: nil, options: [])

// ... 省略 ...

SECTION 201

P.648-649, 定義済みのディレクトリを取得する

「URLForDirectory」メソッドは「url」メソッドに置き換えられました。localDomainMask

func url(for directory: FileManager.SearchPathDirectory, in domain: FileManager.SearchPathDomainMask, appropriateFor url: URL?, create shouldCreate: Bool) throws -> URL

ドメインの定義は先頭の文字が小文字に変更されています。

  • userDomainMask

  • localDomainMask

  • networkDomainMask

  • systemDomainMask

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

do {
    // ドキュメントディレクトリを取得する
    let url = try fm.url(for: .documentDirectory,
        in: .userDomainMask, appropriateFor: nil,
        create: false)

    // コンソールに出力する
    print(url)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.649-650, 取得可能なディレクトリについて

先頭の文字が小文字に変更されています。

P.650, 複数のドメインのURLを一括で取得するには

「URLsForDirectory」メソッドは「urls」メソッドに置き換えられました。

func urls(for directory: FileManager.SearchPathDirectory, in domainMask: FileManager.SearchPathDomainMask) -> [URL]

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 3つのドメインのURLを取得する
let array = fm.urls(for: .libraryDirectory,
    in: [.userDomainMask, .localDomainMask, .systemDomainMask])

// ... 省略 ...

P.651, 定義済みのディレクトリのディレクトリパスを取得するには

サンプルコードを以下の様に変更してください。

import Foundation

// 全アプリケーションディレクトリを取得する
let array = NSSearchPathForDirectoriesInDomains(
    .allApplicationsDirectory, .localDomainMask, true)

// ... 省略 ...

SECTION 202

P.652-653, 「ItemReplacementDirectory」を使った方法について

サンプルコードを以下の様に変更してください。

import Foundation

var fm = FileManager()

do {
    // 本来の保存先のURLを取得する
    let docUrl = try fm.url(for: .documentDirectory,
        in: .userDomainMask,
        appropriateFor: nil, create: false)

    let saveUrl = docUrl.appendingPathComponent("Test.txt")

    // テンポラリディレクトリを取得する
    let url = try fm.url(for: .itemReplacementDirectory,
        in: .userDomainMask,
        appropriateFor: saveUrl,
        create: true)

    // コンソールに出力する
    print(url)

    // 作成したディレクトリを削除する
    try fm.removeItem(at: url)
} catch let error as NSError {
    // 取得したエラー情報を出力する
    print(error)
}

SECTION 203

P.654, ディレクトリを作成する

「createDirectoryAtPath」メソッドは「createDirectory」メソッドに置き換えられました。

func createDirectory(atPath path: String, withIntermediateDirectories createIntermediates: Bool, attributes: [String : Any]? = nil) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 作成するディレクトリのパスを定義する
var path = NSString(string: "~/Test").expandingTildeInPath

do {
    // ディレクトリを作成する
    try fm.createDirectory(atPath: path,
        withIntermediateDirectories: false,
        attributes: nil)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.655, 作成するディレクトリをURLで指定するには

「createDirectoryAtURL」メソッドは「createDirectory」メソッドに置き換えられました。

func createDirectory(at url: URL, withIntermediateDirectories createIntermediates: Bool, attributes: [String : Any]? = nil) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 作成するディレクトリのパスを定義する
var path = NSString(string: "~/Test2").expandingTildeInPath

// URLを取得する
var url = URL(fileURLWithPath: path, isDirectory: true)

do {
    // ディレクトリを作成する
    try fm.createDirectory(at: url,
        withIntermediateDirectories: false, attributes: nil)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 204

P.656, ファイルを作成する

「createFileAtPath」メソッドは「createFile」メソッドに置き換えられました。

func createFile(atPath path: String, contents data: Data?, attributes attr: [String : Any]? = nil) -> Bool

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 作成するファイルのパスを定義する
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// ファイルを作成する
var data = Data(bytes: UnsafePointer<UInt8>("NEW FILE"), count: 8)
fm.createFile(atPath: path, contents: data, attributes: nil)

SECTION 205

P.658, シンボリックリンクを作成する

「createSymbolicLinkAtPath」メソッドは「createSymbolicLink」メソッドに置き換えられました。

func createSymbolicLink(atPath path: String, withDestinationPath destPath: String) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 作成するファイルのパスを定義する
var path = NSString(string: "~/Test.txt").expandingTildeInPath
var symPath = NSString(string: "~/TestSym.txt").expandingTildeInPath

// ファイルを作成する
var data = Data(bytes: UnsafePointer<UInt8>("NEW FILE"), count: 8)
fm.createFile(atPath: path, contents: data, attributes: nil)

do {
    // シンボリックリンクを作成する
    try fm.createSymbolicLink(atPath: symPath,
        withDestinationPath: path)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.659, URLを指定してシンボリックリンクを作成するには

「createSymbolicLinkAtURL」メソッドは「createSymbolicLink」メソッドに置き換えられました。

func createSymbolicLink(at url: URL, withDestinationURL destURL: URL) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 作成するファイルのパスを定義する
var path = NSString(string: "~/Test.txt").expandingTildeInPath
var symPath = NSString(string: "~/TestSym.txt").expandingTildeInPath

// URLを作成する
var url = URL(fileURLWithPath: path)
var symUrl = URL(fileURLWithPath: symPath)

// ファイルを作成する
var data = Data(bytes: UnsafePointer<UInt8>("NEW FILE"), count: 8)
try! data.write(to: url, options: [])

do {
    // シンボリックリンクを作成する
    try fm.createSymbolicLink(at: symUrl, withDestinationURL: url)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 206

P.660-661, シンボリックリンクの指している先を調べる

「destinationOfSymbolicLinkAtPath」メソッドは「destinationOfSymbolicLink」メソッドに置き換えられました。

func destinationOfSymbolicLink(atPath path: String) throws -> String

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 作成するファイルのパスを定義する
var path = NSString(string: "~/Test.txt").expandingTildeInPath
var symPath = NSString(string: "~/TestSym.txt").expandingTildeInPath

// ファイルを作成する
var data = Data(bytes: UnsafePointer<UInt8>("NEW FILE"), count: 8)
try! data.write(to: URL(fileURLWithPath:path), options: [])

do {
    // シンボリックリンクを作成する
    try fm.createSymbolicLink(atPath: symPath,
        withDestinationPath: path)

    // シンボリックリンクが指している先を取得する
    var dst = try fm.destinationOfSymbolicLink(atPath: symPath)

    // コンソールに出力する
    print(dst)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.661-662, シンボリックリンクが指している先をURLで取得するには

「URLByResolvingSymlinksInPath」メソッドは「resolvingSymlinksInPath」メソッドに置き換えられました。

func resolvingSymlinksInPath() -> URL

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 作成するファイルのパスを定義する
var path = NSString(string: "~/Test.txt").expandingTildeInPath
var symPath = NSString(string: "~/TestSym.txt").expandingTildeInPath

// ファイルを作成する
var data = Data(bytes: UnsafePointer<UInt8>("NEW FILE"), count: 8)
try! data.write(to: URL(fileURLWithPath: path), options: [])

do {
    // シンボリックリンクを作成する
    try fm.createSymbolicLink(atPath: symPath, withDestinationPath: path)

    // シンボリックリンクのURLを作成する
    let symUrl = URL(fileURLWithPath: symPath)

    // シンボリックリンクが指しているURLを取得する
    var dstUrl = symUrl.resolvingSymlinksInPath()

    // コンソールに出力する
    print(dstUrl)

} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 207

P.663, ファイルやディレクトリの情報を取得する

「attributesOfItemAtPath」メソッドは「attributesOfItem」メソッドに置き換えられました。

func attributesOfItem(atPath path: String) throws -> [FileAttributeKey : Any]

サンプルコードは以下の様に変更してください。但し、筆者の確認時点では、リンクエラーになってしまい、実行することは出来ませんでした。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 情報を取得するディレクトリのパスを定義
// ここではホームディレクトリを取得する
var path = NSString(string: "~").expandingTildeInPath

do {
    // 情報を取得する
    var attr = try fm.attributesOfItem(atPath: path)

    // コンソールに出力する
    print(attr)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.664-665, ファイル属性キーについて

「FileAttributesKey」として、以下のものが定義されました。

  • appendOnly

  • busy

  • creationDate

  • ownerAccountName

  • groupOwnerAccountName

  • deviceIdentifier

  • extensionHidden

  • groupOwnerAccountID

  • hfsCreatorCode

  • hfsTypeCode

  • immutable

  • modificationDate

  • ownerAccountID

  • posixPermissions

  • referenceCount

  • size

  • systemFileNumber

  • type

  • protectionKey

ファイルタイプについては、以下のものが定義されました。

  • typeDirectory

  • typeRegular

  • typeSymbolicLink

  • typeSocket

  • typeCharacterSpecial

  • typeBlockSpecial

  • typeUnknown

プロテクションキーについては、以下のものが定義されました。

  • none

  • complete

  • completeUnlessOpen

  • completeUntilFirstUserAuthentication

P.665-666, ファイルシステムに関する情報を取得するには

「attributesOfFileSystemForPath」メソッドは「attributesOfFileSystem」メソッドに置き換えられました。

func attributesOfFileSystem(forPath path: String) throws -> [FileAttributeKey : Any]

キーには以下のものが定義されました。

  • systemSize

  • systemFreeSize

  • systemNodes

  • systemFreeNodes

  • systemNumber

サンプルコードは以下の様に変更してください。但し、筆者の確認時点では、リンクエラーになってしまい、実行することは出来ませんでした。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 情報を取得するファイルのパスを定義
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// ファイルを作成する
fm.createFile(atPath: path, contents: nil, attributes: nil)

do {
    // 情報を取得する
    let attr = try fm.attributesOfFileSystem(forPath: path)

    // コンソールに出力する
    print(attr)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.666-667, ファイルやディレクトリの情報を設定するには

サンプルコードを以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// 情報を設定するファイルのパスを定義
var path = NSString(string: "~/Test.txt").expandingTildeInPath

// ファイルを作成する
fm.createFile(atPath: path, contents: nil, attributes: nil)

do {
    // ファイルをロックする
    var attr = [FileAttributeKey.immutable: true]
    try fm.setAttributes(attr, ofItemAtPath: path)

} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.667-668, URLで指定したファイルやディレクトリの情報を設定・取得するには

サンプルコードを以下の様に変更してください。

import Foundation

// ファイルのパスを定義
let path = NSString(string: "~/Test.txt").expandingTildeInPath

// URLを作成
let url = URL(fileURLWithPath: path)

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

// ファイルが存在しないときは作成する
if !fm.fileExists(atPath: path) {
    fm.createFile(atPath: path, contents: nil, attributes: nil)
}

var value: AnyObject?

do {
    // ファイルのロック状態を取得する
    try (url as NSURL).getResourceValue(&value, forKey: URLResourceKey.isUserImmutableKey)
    if let readonly = value as? Bool {
        // ロック状態を反転させる
        try (url as NSURL).setResourceValue(!readonly,
            forKey: URLResourceKey.isUserImmutableKey)
    }
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 208

P.669, ファイルやディレクトリの表示用の名前を取得する

「displayNameAtPath」メソッドは「displayName」メソッドに置き換えられました。

func displayName(atPath path: String) -> String

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

// ドキュメントフォルダのパスを取得する
var array = NSSearchPathForDirectoriesInDomains(.documentDirectory,
    .userDomainMask, true)

// 表示用の名前を取得する
var name = fm.displayName(atPath: array[0])

// コンソールに出力する
print("path = \(array[0])")
print("name = \(name)")

P.670, URLから表示用の名前を取得するには

サンプルコードを以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

do {
    // ドキュメントフォルダのURLを取得する
    let url = try fm.url(for: .documentDirectory,
        in: .userDomainMask,
        appropriateFor: nil, create: false)

    // 表示用の名前を取得する
    var value: AnyObject?
    try (url as NSURL).getResourceValue(&value,
        forKey: URLResourceKey.localizedNameKey)

    // ... 省略 ...
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 209

P.671, ファイルやディレクトリをコピーする

「copyItemAtPath」メソッドは「copyItem」メソッドに置き換えられました。

func copyItem(atPath srcPath: String, toPath dstPath: String) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
var fm = FileManager()

do {
    // テストファイルを作る
    let srcPath = NSString(string: "~/Test.txt").expandingTildeInPath
    try ("TEST FILE").write(toFile: srcPath,
        atomically: true, encoding: String.Encoding.utf8)

    // コピー先
    let dstPath = NSString(string: "~/Test Copy.txt").expandingTildeInPath
    try fm.copyItem(atPath: srcPath, toPath: dstPath)

} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.672, URLで指定したファイルやディレクトリをコピーするには

「copyItemAtURL」メソッドは「copyItem」メソッドに置き換えられました。

func copyItem(at srcURL: URL, to dstURL: URL) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

do {
    // テストファイルを作る
    let srcPath = NSString(string: "~/Test.txt").expandingTildeInPath
    try ("TEST FILE").write(toFile: srcPath,
        atomically: true, encoding: String.Encoding.utf8)

    // コピー元とコピー先のURLを作成する
    let srcUrl = URL(fileURLWithPath: srcPath)

    let dstPath = NSString(string: "~/Test Copy.txt").expandingTildeInPath
    let dstUrl = URL(fileURLWithPath: dstPath)

    // コピーする
    try fm.copyItem(at: srcUrl, to: dstUrl)

} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 210

P.673-674, ファイルやディレクトリを移動する

「moveItemAtPath」メソッドは「moveItem」メソッドに置き換えられました。

func moveItem(at srcURL: URL, to dstURL: URL) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

do {
    // テストファイルを作る
    let srcPath = NSString(string: "~/Test.txt").expandingTildeInPath
    try ("TEST FILE").write(toFile: srcPath,
        atomically: true, encoding: String.Encoding.utf8)

    // 移動先
    let dstPath = NSString(string: "~/Test Moved.txt").expandingTildeInPath

    // 移動
    try fm.moveItem(atPath: srcPath, toPath: dstPath)

} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.674, URLで指定したファイルやディレクトリを移動するには

「moveItemAtURL」メソッドは「moveItem」メソッドに置き換えられました。

func moveItem(at srcURL: URL, to dstURL: URL) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

do {
    // テストファイルを作る
    let srcPath = NSString(string: "~/Test.txt").expandingTildeInPath
    try ("TEST FILE").write(toFile: srcPath,
        atomically: true, encoding: String.Encoding.utf8)

    // 移動元と移動先のURLを作成する
    let srcUrl = URL(fileURLWithPath: srcPath)

    let dstPath = NSString(string: "~/Test Moved.txt").expandingTildeInPath
    let dstUrl = URL(fileURLWithPath: dstPath)

    // コピーする
    try fm.moveItem(at: srcUrl, to: dstUrl)

} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 211

P.676, ファイルやディレクトリを削除する

「removeItemAtPath」メソッドは「removeItem」メソッドに置き換えられました。

func removeItem(atPath path: String) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

do {
    // 削除する項目
    let path = NSString(string: "~/DeleteTest").expandingTildeInPath

    // 削除
    try fm.removeItem(atPath: path)

} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.677, 削除するファイルやディレクトリをURLで指定するには

「removeItemAtURL」メソッドは「removeItem」メソッドに置き換えられました。

func removeItem(at URL: URL) throws

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

do {
    // 削除する項目
    let path = NSString(string: "~/DeleteTest").expandingTildeInPath
    let url = URL(fileURLWithPath: path)

    // 削除
    try fm.removeItem(at: url)

} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 212

P.678, ファイルやディレクトリが存在するか調べる

「fileExistsAtPath」メソッドは「fileExists」メソッドに置き換えられました。

func fileExists(atPath path: String) -> Bool

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

// 「/System/Library」ディレクトリが存在するか調べる
let path1 = "/System/Library"
let isExist = fm.fileExists(atPath: path1)

// 「/System/Library_」ディレクトリが存在するか調べる
let path2 = "/System/Library_"
let isExist2 = fm.fileExists(atPath: path2)

// ... 省略 ...

P.679, 指定された項目がディレクトリかどうかを判定するには

「fileExistsAtPath」メソッドは「fileExists」メソッドに置き換えられました。

func fileExists(atPath path: String, isDirectory: UnsafeMutablePointer<ObjCBool>?) -> Bool

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

// 「/System/Library」ディレクトリが存在するか調べる
let path = "/System/Library"
var isDir = ObjCBool(false)
let isExist = fm.fileExists(atPath: path, isDirectory: &isDir)

// ... 省略 ...

SECTION 213

P.680, 読み込み可能なファイルかを調べる

「isReadableFileAtPath」メソッドは「isReadableFile」メソッドに置き換えられました。

func isReadableFile(atPath path: String) -> Bool

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

// 「~/Normal.txt」が読み込み可能か調べる
let path = NSString(string: "~/Normal.txt").expandingTildeInPath
let possible = fm.isReadableFile(atPath: path)

// 「~/WriteOnly.txt」が読み込み可能か調べる
let path2 = NSString(string: "~/WriteOnly.txt").expandingTildeInPath
let possible2 = fm.isReadableFile(atPath: path2)

// ... 省略 ...

SECTION 214

P.682, 書き込み可能なファイルかを調べる

「isWritableFileAtPath」メソッドは「isWritableFile」メソッドに置き換えられました。

func isWritableFile(atPath path: String) -> Bool

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

// 「~/Normal.txt」が書き込み可能か調べる
let path = NSString(string: "~/Normal.txt").expandingTildeInPath
let possible = fm.isWritableFile(atPath: path)

// 「~/ReadOnly.txt」が書き込み可能か調べる
let path2 = NSString(string: "~/ReadOnly.txt").expandingTildeInPath
let possible2 = fm.isWritableFile(atPath: path2)

// ... 省略 ...

SECTION 215

P.684, 削除可能なファイルかを調べる

「isDeletableFileAtPath」メソッドは「isDeletableFile」メソッドに置き換えられました。

func isDeletableFile(atPath path: String) -> Bool

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

// 「~/Normal.txt」が削除可能か調べる
let path = NSString(string: "~/Normal.txt").expandingTildeInPath
let possible = fm.isDeletableFile(atPath: path)

// 「~/LockedDir/Normal.txt」が削除可能か調べる
let path2 = NSString(string: "~/LockedDir/Normal.txt").expandingTildeInPath
let possible2 = fm.isDeletableFile(atPath: path2)

// ... 省略 ...

SECTION 216

P.686, 実行可能なファイルかを調べる

「isExecutableFileAtPath」メソッドは「isExecutableFile」メソッドに置き換えられました。

func isExecutableFile(atPath path: String) -> Bool

サンプルコードは以下の様に変更してください。

import Foundation

// ファイルマネージャーのインスタンス確保
let fm = FileManager()

// 「~/Normal.txt」が実行可能か調べる
let path = NSString(string: "~/Normal.txt").expandingTildeInPath
let possible = fm.isExecutableFile(atPath: path)

// 「~/Script」が実行可能か調べる
let path2 = NSString(string: "~/Script").expandingTildeInPath
let possible2 = fm.isExecutableFile(atPath: path2)

// ... 省略 ...

SECTION 217

P.688-689, インスタンスをシリアライズする

「archivedDataWithRootObject」メソッドは「archivedData」メソッドに置き換えられました。

class func archivedData(withRootObject rootObject: Any) -> Data

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// シリアライズしたデータを作る
var data = NSKeyedArchiver.archivedData(withRootObject: numArray)

// ファイルに保存する
var path = NSString(string: "~/NumArray.dat").expandingTildeInPath
(data as NSData).write(toFile: path, atomically: true)

P.690, インスタンスをシリアライズしたファイルを作るには

サンプルコードを以下の様に変更してください。

// ... 省略 ...

// シリアライズしたデータを作る
var path = NSString(string: "~/NumArray").expandingTildeInPath
var data = NSKeyedArchiver.archivedData(withRootObject: numArray)
NSKeyedArchiver.archiveRootObject(numArray, toFile: path)

SECTION 218

P.691, シリアライズしたインスタンスを読み込む

「unarchiveObjectWithData」メソッドは「unarchiveObject」メソッドに置き換えられました。

class func unarchiveObject(with data: Data) -> Any?

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// シリアライズしたデータを作る
var data = NSKeyedArchiver.archivedData(withRootObject: numArray)

// データを読み込んで、インスタンスを作る
// (「numArray」と同じものが出来る)
var newArray = NSKeyedUnarchiver.unarchiveObject(with: data)

// コンソールに出力する
print(newArray)

P.692, シリアライズしたファイルを読み込む

「unarchiveObjectWithFile」メソッドは「unarchiveObject」メソッドに置き換えられました。

// ... 省略 ...

// シリアライズしたデータを作る
var path = NSString(string: "~/NumArray").expandingTildeInPath
var data = NSKeyedArchiver.archivedData(withRootObject: numArray)
NSKeyedArchiver.archiveRootObject(numArray, toFile: path)

// データを読み込んで、インスタンスを作る
// (「numArray」と同じものが出来る)
var newArray = NSKeyedUnarchiver.unarchiveObject(withFile: path)

// コンソールに出力する
print(newArray)

SECTION 219

P.693-694, 独自のクラスをアーカイバ対応にする

「encodeWithCoder」メソッドは「encode」メソッドに置き換えられました。

func encode(with aCoder: NSCoder)

サンプルコードは以下の様に変更してください。

// ... 省略 ...
@objc(ArchiverTest)
public class ArchiverTest : NSObject, NSCoding {

    // ... 省略 ...

    // シリアライズしたデータからインスタンスを生成するときに使用するメソッド
    public required convenience init?(coder aDecoder: NSCoder) {
        // 初期化する
        self.init();

        // 文字列を読み込む
        if let str = aDecoder.decodeObject(forKey: "message") as? String {
            message = str
        }
    }

    // インスタンスをシリアライズする
    public func encode(with aCoder: NSCoder) {
        // 文字列をシリアライズする
        aCoder.encode(self.message, forKey: "message")
    }
}

// ... 省略 ...

// シリアライズする
var data = NSKeyedArchiver.archivedData(withRootObject: obj)

// デコードする
if let sub2 =
    NSKeyedUnarchiver.unarchiveObject(with: data) as? ArchiverTest {
        // ... 省略 ...
}

P.695, 情報の読み書きメソッドについて

「NSCoder」クラスの対応するメソッドの定義が変更されています。詳細はSDKのドキュメントを参照してください。

P.696-698, 派生クラスでもアーカイバに対応した処理を実装するには

サンプルコードを以下の様に変更してください。

// ... 省略 ...
@objc(ArchiverTest)
public class ArchiverTest : NSObject, NSCoding {
    // ... 省略 ...

    // シリアライズしたデータからインスタンスを生成するときに使用するメソッド
    public required convenience init?(coder aDecoder: NSCoder) {
        // 別定義したイニシャライザを呼ぶ
        self.init(decoder: aDecoder)
    }

    // シリアライズしたデータのデコード処理
    // 派生クラスから呼べるようにDesignatedイニシャライザとする
    public init(decoder aDecoder: NSCoder) {
        // 初期化する
        super.init();

        // 文字列を読み込む
        if let str = aDecoder.decodeObject(forKey: "message") as? String {
            message = str
        }
    }

    // インスタンスをシリアライズする
    public func encode(with aCoder: NSCoder) {
        // 文字列をシリアライズする
        aCoder.encode(self.message, forKey: "message")
    }
}

// サブクラスを定義する
@objc(ArchiverTestSub)
public class ArchiverTestSub : ArchiverTest {

    // ... 省略 ...

    // シリアライズしたデータからインスタンスを生成するときに使用するメソッド
    public convenience required init?(coder aDecoder: NSCoder) {
        // 別定義したイニシャライザを呼ぶ
        self.init(decoder: aDecoder)
    }

    // シリアライズしたデータのデコード処理
    public override init(decoder aDecoder: NSCoder) {
        // 親クラスの処理を呼ぶ
        super.init(decoder: aDecoder)

        // 整数をデコードする
        self.number = aDecoder.decodeInteger(forKey: "number")
    }

    // インスタンスをシリアライズする
    public override func encode(with aCoder: NSCoder) {
        // 親クラスの処理を呼ぶ
        super.encode(with: aCoder)

        // 整数をエンコードする
        aCoder.encode(self.number, forKey: "number")
    }
}

// ... 省略 ...

// シリアライズする
var data = NSKeyedArchiver.archivedData(withRootObject: obj)

// デコードする
if let obj2 =
    NSKeyedUnarchiver.unarchiveObject(with: data) as? ArchiverTestSub {
        // ... 省略 ...
}

SECTION 220

P.699, プロパティリストデータを作成する

「NSPropertyListSerialization」は「PropertyListSerialization」に置き換えられました。フォーマットの定数は以下のものが定義されました。

  • openStep

  • xml

  • binary

「dataWithPropertyList」メソッドは「data」メソッドに置き換えられました。

class func data(fromPropertyList plist: Any, format: PropertyListSerialization.PropertyListFormat, options opt: WriteOptions) throws -> Data

サンプルコードは以下の様に変更してください。

import Foundation

// プロパティリストにするディクショナリを作成する
var dict = ["LangName":"Swift", "Vers":1.2] as [String : Any]

do {
    // プロパティリストのデータを作成する
    let data = try PropertyListSerialization.data(fromPropertyList:
        dict, format: .xml, options: 0)

    // ファイルに書き出す
    var path = NSString(string: "~/Dict.plist").expandingTildeInPath
    (data as NSData).write(toFile: path, atomically: true)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

P.700, プロパティリストファイルを作成するには

「writeToFile」メソッドと「writeToURL」メソッドは「write」メソッドに置き換えられました。

func write(toFile path: String, atomically useAuxiliaryFile: Bool) -> Bool
func write(to url: URL, atomically: Bool) -> Bool

SECTION 221

P.701-702, プロパティリストデータを読み込む

「propertyListWithData」メソッドは「propertyList」メソッドに置き換えられました。

class func propertyList(from data: Data, options opt: ReadOptions = [], format: UnsafeMutablePointer<PropertyListSerialization.PropertyListFormat>?) throws -> Any

オプションは以下のものが定義されました。

  • mutableContainers

  • mutableContainersAndLeaves

サンプルコードは以下の様に変更してください。

import Foundation

// プロパティリストにするディクショナリを作成する
var dict = ["LangName":"Swift", "Vers":1.2] as [String : Any]

do {
    // プロパティリストのデータを作成する
    let data = try PropertyListSerialization.data(
        fromPropertyList: dict, format: .xml, options: 0)

    // この変数は「propertyListWithData」が情報を格納する先として使うだけなので、
    // 値自体は有効な値なら何でも良い
    var format = PropertyListSerialization.PropertyListFormat.binary

    // 作成したデータを読み込んで、インスタンスを生成する
    var dict2 = try PropertyListSerialization.propertyList(from: data,
        options: [], format: &format)

    // コンソールに出力する
    print(dict2)
} catch let error as NSError {
    // エラー情報を出力する
    print(error)
}

SECTION 222

P.703, プロパティリストに変換可能かを調べる

サンプルコードを以下の様に変更してください。

import Foundation

// ディクショナリを作成する
var dict = ["LangName":"Swift", "Vers":1.2] as [String : Any]
var dict2 = ["Comment":"Has Index Set", "indexset":IndexSet()] as [String : Any]

// プロパティリストに変換可能かを調べる
var b = PropertyListSerialization.propertyList(dict,
    isValidFor: .xml)
var b2 = PropertyListSerialization.propertyList(dict2,
    isValidFor: .xml)

// ... 省略 ...

SECTION 224

P.708, URLへの接続要求を作成する

イニシャライザは次のように変更されました。

init(url: URL, cachePolicy: CachePolicy = default, timeoutInterval: TimeInterval = default)

サンプルコードは以下の様に変更してください。

import Foundation

// 接続先のURL
if let url = URL(string: "http://www.rk-k.com/test/test.txt") {
    // 接続要求を作成する
    var req = NSURLRequest(url: url)

    // コンソールに出力する
    print(req)
}

P.709-710, HTTPのヘッダを設定するには

サンプルコードを以下の様に変更してください。

import Foundation

// 接続先のURL
if let url = URL(string: "http://www.rk-k.com/test/test.txt") {
    // 接続要求を作成する
    var req = NSMutableURLRequest(url: url)

    // ... 省略 ...
}

P.710, HTTPのメソッドを設定するには

「HTTPMethod」プロパティは「httpMethod」に変更されました。

var httpMethod: String { get set }

サンプルコードは以下の様に変更してください。

import Foundation

// 接続先のURL
if let url = URL(string: "http://www.rk-k.com/test/test.txt") {
    // 接続要求を作成する
    var req = NSMutableURLRequest(url: url)

    // メソッドを「POST」にする
    req.httpMethod = "POST"
}

P.710-711, HTTPのボディデータを設定するには

「HTTPBodyStream」プロパティは「httpBodyStream」プロパティ、「HTTPBody」プロパティは「httpBody」プロパティに変更されました。

var httpBody: Data? { get set }
var httpBodyStream: InputStream? { get set }

P.711, 接続時のタイムアウトやキャッシュポリシーを指定するには

定数の先頭文字が小文字に変更されています。

SECTION 225

P.712-713, ダウンロードタスクを使ってダウンロードする

「NSURLSession」は「URLSession」、「NSURLSessionConfiguration」は「URLSessionConfiguration」、「NSHTTPURLResponse」は「HTTPURLResponse」、「downloadTaskWithRequest」メソッドは「downloadTask」メソッドに変更されました。

func downloadTask(with request: URLRequest, completionHandler: @escaping (URL?, URLResponse?, Error?) -> Void) -> URLSessionDownloadTask

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動時の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // 接続先のURL
        if let url = URL(string: "http://www.rk-k.com/test/test.txt") {
            // 接続要求を作成する
            let req = NSURLRequest(url: url)

            // セッションを作成する
            let config = URLSessionConfiguration.default
            let session = URLSession(configuration: config)

            // ダウンロードタスクを作る
            let task = session.downloadTask(with: req as URLRequest,
                completionHandler: { (location, resp, error) -> Void in
                    // 完了時の処理
                    // エラーチェックとHTTPのステータスコードをチェックする
                    var statusCode = 0
                    if let httpResp = resp as? HTTPURLResponse {
                        statusCode = httpResp.statusCode
                    }

                    if statusCode == 200 && error == nil {

                        do {
                            // テンポラリファイルからテキストデータとして読み込む
                            let text = try String(contentsOf: location!,
                                encoding: .utf8)

                            // コンソールに出力する
                            print(text)
                        } catch let error as NSError {
                            // エラー情報を出力する
                            print(error)
                        }
                    }
            })

            // タスクを開始する
            task.resume()
        }
    }

}

P.225, セッションの作成について

「URLSessionConfiguration」では、以下のプロパティとメソッドが定義されています。

class var `default`: URLSessionConfiguration { get }
class var ephemeral: URLSessionConfiguration { get }
class func background(withIdentifier identifier: String) -> URLSessionConfiguration

SECTION 226

P.716-717, アップロードタスクを使ってアップロードする

「uploadTaskWithRequest」メソッドは「uploadTask」メソッドに変更されました。

func uploadTask(with request: URLRequest, fromFile fileURL: URL, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionUploadTask

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動時の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // 接続先のURL
        if let url = URL(string: "http://localhost:8080/CH11Web/UploadTask") {

            do {
                // 接続要求を作成する
                let req = NSMutableURLRequest(url: url)

                // メソッドをPOSTにする
                req.httpMethod = "POST"

                // ボディデータを作る
                let dict = ["Param1": "1", "Param2": "Test"]
                let bodyData = try JSONSerialization.data(withJSONObject: dict,
                    options: .prettyPrinted)

                // セッションを作成する
                let config = URLSessionConfiguration.default
                let session = URLSession(configuration: config)

                // アップロードタスクを作る
                let task = session.uploadTask(with: req as URLRequest, from: bodyData,
                    completionHandler: { (respData, resp, error) -> Void in
                        // 完了時の処理。このサンプルでは特に何もしない
                        var str = String(data: respData!, encoding: .utf8)
                        print(str)
                })

                // タスクを開始する
                task.resume()
            } catch let error as NSError {
                // エラー情報を出力する
                print(error)
            }
        }
    }

}

SECTION 227

P.719-720, データタスクを使って通信を行う

「dataTaskWithRequest」メソッドは「dataTask」メソッドに変更されました。

func dataTask(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask

サンプルコードは以下の様に変更してください。

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet weak var window: NSWindow!

    // アプリ起動時の処理
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // 接続先のURL
        if let url = URL(string: "http://localhost:8080/CH11Web/DataTask") {

            do {
                // 接続要求を作成する
                let req = NSMutableURLRequest(url: url)

                // メソッドをPOSTにする
                req.httpMethod = "POST"

                // ボディデータを作る
                let dict = ["NumberArray": [1, 2, 3, 4, 5]]
                let bodyData = try JSONSerialization.data(withJSONObject: dict,
                    options: .prettyPrinted)

                // ボディデータを設定する
                req.httpBody = bodyData

                // セッションを作成する
                let config = URLSessionConfiguration.default
                let session = URLSession(configuration: config)

                // データタスクを作る
                let task = session.dataTask(with: req as URLRequest,
                    completionHandler: { (respData, resp, error) -> Void in
                        // 完了時の処理。レスポンスデータを文字列化してコンソールに出力する
                        if respData != nil {
                            let text = String(data: respData!, encoding: .utf8)
                            print(text)
                        }
                })

                // タスクを開始する
                task.resume()
            } catch let error as NSError {
                // エラー情報を出力する
                print(error)
            }
        }
    }

}

SECTION 228

P.722, 設定情報をユーザーデフォルトに保存する

「NSUserDefaults」は「UserDefaults」に変更されました。「standardUserDefaults」メソッドは「standard」プロパティに置き換えられました。設定用のメソッドも定義が変更されています。

class var standard: UserDefaults { get }

func set(_ value: Bool, forKey defaultName: String)
func set(_ value: Float, forKey defaultName: String)
func set(_ value: Int, forKey defaultName: String)
func set(_ value: Any?, forKey defaultName: String)
func set(_ value: Double, forKey defaultName: String)
func set(_ url: URL?, forKey defaultName: String)

サンプルコードは以下の様に変更してください。

import Foundation

// ユーザーデフォルトを取得する
var ud = UserDefaults.standard

// 「level」というキーで「2」を保存する
ud.set(2, forKey: "level")

// 「name」というキーで「Player」を保存する
ud.set("Player", forKey: "name")

SECTION 229

P.724-725, 設定情報をユーザーデフォルトから取得する

取得用のメソッドの定義が変更されています。

func array(forKey defaultName: String) -> [Any]?
func bool(forKey defaultName: String) -> Bool
func data(forKey defaultName: String) -> Data?
func dictionary(forKey defaultName: String) -> [String : Any]?
func float(forKey defaultName: String) -> Float
func integer(forKey defaultName: String) -> Int
func object(forKey defaultName: String) -> Any?
func stringArray(forKey defaultName: String) -> [String]?
func string(forKey defaultName: String) -> String?
func double(forKey defaultName: String) -> Double
func url(forKey defaultName: String) -> URL?

サンプルコードは以下の様に変更してください。

import Foundation

// ユーザーデフォルトを取得する
var ud = Foundation.UserDefaults.standard

// 「level」というキーで「2」を保存する
ud.set(2, forKey: "level")

// 「name」というキーで「Player」を保存する
ud.set("Player", forKey: "name")

// 保存した情報を取得する
var level = ud.integer(forKey: "level")
var name = ud.string(forKey: "name")

// ... 省略 ...

SECTION 230

P.726-727, 初期値をユーザーデフォルトに登録する

「registerDefaults」メソッドは「register」メソッドに変更されました。

func register(defaults registrationDictionary: [String : Any])

サンプルコードは以下の様に変更してください。

import Foundation

// ユーザーデフォルトを取得する
var ud = Foundation.UserDefaults.standard

// 初期値を登録する
var dict = ["title": "untitled", "color": "gray"]
ud.register(defaults: dict)

// 初期値を登録したキーの値を取得する
var title = ud.string(forKey: "title")
var color = ud.string(forKey: "color")

// コンソールに出力する
print("title = \(title)")
print("color = \(color)")

// 値を変更する
ud.set("Swift", forKey: "title")

// 値を取得する
title = ud.string(forKey: "title")

// コンソールに出力する
print("title = \(title)")

SECTION 231

P.728-729, 設定情報を削除する

「removeObjectForKey」メソッドは「removeObject」メソッドに変更されました。

func removeObject(forKey defaultName: String)

サンプルコードは以下の様に変更してください。

import Foundation

// ユーザーデフォルトを取得する
var ud = Foundation.UserDefaults.standard

// 値を設定する
ud.set("Swift", forKey: "title")

// 値を取得する
var title = ud.string(forKey: "title")

// コンソールに出力する
print("title = \(title)")

// 設定値を削除する
ud.removeObject(forKey: "title")

// 値を取得する
title = ud.string(forKey: "title")

// コンソールに出力する
print("title = \(title)")

SECTION 232

P.730-731, 設定情報をディクショナリにして取得する

サンプルコードを以下の様に変更してください。

import Foundation

// ユーザーデフォルトを取得する
var ud = UserDefaults.standard

// 初期値を登録する
var dict = ["title": "Untitled"]
ud.register(defaults: dict)

// 値を設定する
ud.set("White", forKey: "color")

// ... 省略 ...

SECTION 233

P.732-733, ノーティフィケーションを投げる

「NSNotificationCenter」は「NotificationCenter」に変更されました。ノーティフィケーションを投げるメソッドは以下の様に定義が変更されています。

func post(name aName: NSNotification.Name, object anObject: Any?)

func post(name aName: NSNotification.Name, object anObject: Any?, userInfo aUserInfo: [AnyHashable : Any]? = nil)

func post(_ notification: Notification)

サンプルコードは以下の様に変更してください。

Notifier.swift

//... 省略 ..
class Notifier: NSObject {
    func post() {
        // ノーティフィケーションセンターを取得する
        let center = NotificationCenter.default

        // 通知を投げる
        center.post(name: NSNotification.Name(NotifierTestNotification), object: self)
    }

}

SECTION 234

P.734-735, ノーティフィケーションを受信する

サンプルコードを以下の様に変更してください。

Notifier.swift

//... 省略 ...
class Notifier: NSObject {
    func post() {
        // ノーティフィケーションセンターを取得する
        let center = NotificationCenter.default

        // 通知を投げる
        center.post(name: Notification.Name(NotifierTestNotification), object: self)
    }

}

Observer.swift

import Foundation

class Observer: NSObject {

    // インスタンス解放時の処理
    deinit {
        // ノーティフィケーションの通知受け取り解除
        let center = NotificationCenter.default
        center.removeObserver(self)
    }

    // ノーティフィケーションの受信準備
    func setupObserver() {
        // ノーティフィケーションを受信する
        let center = NotificationCenter.default
        center.addObserver(self, selector: #selector(Observer.testNotification(_:)),
            name: NSNotification.Name(NotifierTestNotification), object: nil)
    }

    // ノーティフィケーション受信時の処理
    func testNotification(_ notification: Notification) {
        // コンソールにメッセージを表示する
        print("Received Notification")
    }
}

P.736-738, 追加情報を取得するには

サンプルコードを以下の様に変更してください。

Notifier.swift

// ... 省略 ...
class Notifier: NSObject {

    // ... 省略 ...
    func post() {
        // ノーティフィケーションセンターを取得する
        let center = NotificationCenter.default

        // 付与する情報を作る
        let userInfo = [NotifierMessage: self.message]

        // 通知を投げる
        center.post(name: Notification.Name(NotifierTestNotification), object: self,
            userInfo: userInfo)
    }

}

Observer.swift

import Foundation

class Observer: NSObject {

    // インスタンス解放時の処理
    deinit {
        // ノーティフィケーションの通知受け取り解除
        let center = NotificationCenter.default
        center.removeObserver(self)
    }

    // ノーティフィケーションの受信準備
    func setupObserver() {
        // ノーティフィケーションを受信する
        let center = NotificationCenter.default
        center.addObserver(self, selector: #selector(Observer.testNotification(_:)),
            name: NSNotification.Name(NotifierTestNotification), object: nil)
    }

    // ノーティフィケーション受信時の処理
    func testNotification(_ notification: Notification) {
        // 追加情報を取得する
        if let userInfo = (notification as NSNotification).userInfo {
            // 付与されたメッセージを取得する
            if let msg = userInfo[NotifierMessage] as? String {
                // コンソールにメッセージを表示する
                print(msg)
            }
        }
    }
}

P.738-740, ノーティフィケーションを投げたオブジェクトでフィルタリングするには

サンプルコードを以下の様に変更してください。

Notifier.swift

// ... 省略 ...
class Notifier: NSObject {

    // ... 省略 ...
    func post() {
        // ノーティフィケーションセンターを取得する
        let center = NotificationCenter.default

        // 付与する情報を作る
        let userInfo = [NotifierMessage: self.message]

        // 通知を投げる
        center.post(name: Notification.Name(NotifierTestNotification), object: self,
            userInfo: userInfo)
    }

}

Observer.swift

import Foundation

class Observer: NSObject {

    // インスタンス解放時の処理
    deinit {
        // ノーティフィケーションの通知受け取り解除
        let center = NotificationCenter.default
        center.removeObserver(self)
    }

    // ノーティフィケーションの受信準備
    func setupObserver(_ notifier: AnyObject) {
        // ノーティフィケーションを受信する
        let center = NotificationCenter.default
        center.addObserver(self, selector: #selector(Observer.testNotification(_:)),
            name: NSNotification.Name(NotifierTestNotification), object: notifier)
    }

    // ノーティフィケーション受信時の処理
    func testNotification(_ notification: Notification) {
        // 追加情報を取得する
        if let userInfo = (notification as NSNotification).userInfo {
            // 付与されたメッセージを取得する
            if let msg = userInfo[NotifierMessage] as? String {
                // コンソールにメッセージを表示する
                print(msg)
            }
        }
    }
}

SECTION 235

P.742-743, ランループを取得する

「NSRunLoop」は「RunLoop」に変更されました。「currentRunLoop」メソッドは「current」プロパティに変更されました。

class var current: RunLoop { get }

サンプルコードは以下の様に変更してください。

import Foundation

// 現在のランループ(実行中のスレッドのランループ)を取得する
var runLoop = RunLoop.current

// コンソールに出力する
print(runLoop)

P.743, メインランループを取得するには

「mainRunLoop」メソッドは「main」プロパティに変更されました。

class var main: RunLoop { get }

SECTION 236

P.744-745, ランループを手動で実行する

「runUntilDate」メソッドは「run」メソッドに変更されました。

func run(until limitDate: Date)

サンプルコードは以下の様に変更してください。

import Foundation

// 現在のランループ(実行中のスレッドのランループ)を取得する
var runLoop = RunLoop.current

// 現在の日時を取得する
var startDate = Date()

var isContinue = true
while isContinue {
    // どのような処理が呼ばれるか分からないため
    // 念のため、自動解放プールを使う
    autoreleasepool {
        // ランループを0.5秒実行する
        print("will runUntilDate \(NSDate())")
        runLoop.run(until: Date(timeIntervalSinceNow: 0.5))
        print("did runUntilDate  \(NSDate())")

        // 経過時間を取得する
        var dt = NSDate().timeIntervalSince(startDate)
        if dt > 5 {
            // 5秒以上経過したので終了
            isContinue = false;
        }
    }
}

print("Terminate")

P.746, モードを指定して手動実行するには

「runMode」メソッドは「run」メソッドに変更されました。

func run(mode: RunLoopMode, before limitDate: Date) -> Bool

モードは以下のものに変更されました。

  • commonModes

  • defaultRunLoopMode

  • eventTrackingRunLoopMode

  • modalPanelRunLoopMode

SECTION 237

P.747-749, タイマーを作成する

「NSTimer」は「Timer」に変更されました。「scheduledTimerWithTimeInterval」メソッドは「scheduledTimer」メソッドに変更されました。

class func scheduledTimer(timeInterval ti: TimeInterval, target aTarget: Any, selector aSelector: Selector, userInfo: Any?, repeats yesOrNo: Bool) -> Timer

サンプルコードは以下の様に変更してください。

CountDown.swift

import Foundation

// カウントダウンを行うクラス
class CountDown: NSObject {
    // カウンター
    var counter: Int = 5

    // タイマー
    var timer: Timer?

    // カウントダウンを開始するメソッド
    func startCountDown() {
        // タイマーを作成する
        // ここでは1秒ごとに呼び出すタイマーを作っている
        self.timer = Timer.scheduledTimer(timeInterval: 1,
            target: self, selector: #selector(CountDown.countDownByTimer(_:)),
            userInfo: nil, repeats: true)

        // 開始時のカウンターを出力する
        print(self.counter)
    }

    // タイマーで実行するメソッド
    func countDownByTimer(_ timer: Timer) {
        // ... 省略 ...
    }
}

main.swift

import Foundation

// インスタンスを確保する
var countDown = CountDown()

// カウントダウンを開始する
countDown.startCountDown()

// ランループを取得する
var runLoop = RunLoop.current

// 開始時刻を取得する
var startDate = Date()

// 7秒経過するまでランループを手動実行する
// コンソールアプリのために手動実行しているが、
// CocoaやCocoa touchのアプリでは自動実行されている
var isContinue = true
while isContinue {
    autoreleasepool{
        // 経過時間を取得する
        var dt = Date().timeIntervalSince(startDate)

        if dt > 7 {
            // 7秒以上経過したら終了
            isContinue = false
        }

        // ランループを実行する
        runLoop.run(until: Date(timeIntervalSinceNow: 0.1))
    }
}

P.749-751, 作成時に指定した追加情報を取得するには

サンプルコードを以下の様に変更してください。

Delay.swift

import Foundation

// タイマーで実行する処理を実装したクラス
class Delay: NSObject {
    // タイマーの配列
    var timers: [Timer] = []

    // タイマーを作成する
    func startTimers() {
        // 1秒ごとに実行するタイマーを作る
        var timer = Timer.scheduledTimer(timeInterval: 1,
            target: self, selector: #selector(Delay.timerProc(_:)),
            userInfo: "Timer A", repeats: true)
        timers.append(timer)

        // 0.4秒ごとに実行するタイマーを作る
        timer = Timer.scheduledTimer(timeInterval: 0.4,
            target: self, selector: #selector(Delay.timerProc(_:)),
            userInfo: "Timer B", repeats: true)
        timers.append(timer)

        // 1.2秒ごとに実行するタイマーを作る
        timer = Timer.scheduledTimer(timeInterval: 1.2,
            target: self, selector: #selector(Delay.timerProc(_:)),
            userInfo: "Timer C", repeats: true)
        timers.append(timer)
    }

    // タイマーで実行するメソッド
    func timerProc(_ timer: Timer) {
        // 追加情報を取得する。このサンプルでは文字列として取得する
        if let str = timer.userInfo as? String {
            // コンソールに出力する
            print(str)
        }
    }
}

main.swift

import Foundation

// インスタンスを確保する
var delay = Delay()

// タイマーを開始する
delay.startTimers()

// ランループを取得する
var runLoop = RunLoop.current

// 開始時刻を取得する
var startDate = Date()

// 5秒経過するまでランループを手動実行する
// コンソールアプリのために手動実行しているが、
// CocoaやCocoa touchのアプリでは自動実行されている
var isContinue = true
while isContinue {
    autoreleasepool{
        // 経過時間を取得する
        var dt = NSDate().timeIntervalSince(startDate)

        if dt > 5 {
            // 5秒以上経過したら終了
            isContinue = false
        }

        // ランループを実行する
        runLoop.run(until: Date(timeIntervalSinceNow: 0.1))
    }
}

P.752, 任意のランループで任意のランループモードでタイマーをセットするには

イニシャライザは以下の様に変更されています。

init(fireAt date: Date, interval ti: TimeInterval, target t: Any, selector s: Selector, userInfo ui: Any?, repeats rep: Bool)

init(timeInterval ti: TimeInterval, target aTarget: Any, selector aSelector: Selector, userInfo: Any?, repeats yesOrNo: Bool)

「addTimer」メソッドは「add」メソッドに変更されています。

func add(_ timer: Timer, forMode mode: RunLoopMode)

P.752-754, 遅延処理の実装にタイマーを使う

サンプルコードを以下の様に変更してください。

Delay.swift

import Foundation

// タイマーで実行する処理を実装したクラス
class Delay: NSObject {
    // タイマー
    var timer: Timer?

    // 終了フラグ
    var exit: Bool = false

    // タイマーの作成または遅延
    func delayOperation() {
        // タイマーが作成済みか?
        if self.timer != nil {
            // 作成済みなので、実行時間を1秒後にセットする
            self.timer!.fireDate = Date(timeIntervalSinceNow: 1)
        } else {
            // タイマーを作成する
            self.timer = Timer.scheduledTimer(timeInterval: 1,
                target: self, selector: #selector(Delay.timerProc(_:)),
                userInfo: nil, repeats: false)
        }
    }

    // タイマーで実行するメソッド
    func timerProc(_ timer: Timer) {
        // コンソールにメッセージを出力する
        print("The timer is fired")

        // 終了フラグをセット
        self.exit = true
    }
}

main.swift

import Foundation

// インスタンスを確保する
var delay = Delay()

// ランループを取得する
var runLoop = RunLoop.current

// 開始日時を取得
var startDate = Date()

// ランループを手動実行する
// コンソールアプリのために手動実行しているが、
// CocoaやCocoa touchのアプリでは自動実行されている
while !delay.exit {
    autoreleasepool{
        // 経過時間を取得する
        var dt = NSDate().timeIntervalSince(startDate)

        // 3秒以内なら遅延させる
        if dt <= 3 {
            delay.delayOperation()
        }

        // コンソールに「.」を出力
        print(".")

        // ランループを実行する
        runLoop.run(until: Date(timeIntervalSinceNow: 0.1))
    }
}

// 経過日時を取得
var dt = NSDate().timeIntervalSince(startDate)

// コンソールに出力
print("\(dt) sec")

SECTION 238

P.755-756, タイマーを停止する

サンプルコードを以下の様に変更してください。

Delay.swift

import Foundation

// タイマーで実行する処理を実装したクラス
class Delay: NSObject {
    // タイマー
    var timer: Timer?

    // タイマーの作成
    func startTimer() {
        self.timer = Timer.scheduledTimer(timeInterval: 1,
            target: self, selector: #selector(Delay.timerProc(_:)),
            userInfo: nil, repeats: true)
    }

    // タイマーで実行するメソッド
    func timerProc(_ timer: Timer) {
        // コンソールに文字列を出力
        print(".")
    }
}

main.swift

import Foundation

// インスタンスを確保する
var delay = Delay()

// タイマー開始
delay.startTimer()

// ランループを取得する
var runLoop = RunLoop.current

// 開始日時を取得
var startDate = Date()

// ランループを手動実行する
// コンソールアプリのために手動実行しているが、
// CocoaやCocoa touchのアプリでは自動実行されている
var isContinue = true
while isContinue {
    autoreleasepool{
        // ランループを実行する
        runLoop.run(until: Date(timeIntervalSinceNow: 0.1))

        // 5秒を超えたらタイマー停止
        var dt = NSDate().timeIntervalSince(startDate)

        // ... 省略 ...
    }
}
// ... 省略 ...

SECTION 239

P.757-758, オペレーションキューを作成する

「NSOperationQueue」は「OperationQueue」、「NSThread」は「Thread」に変わりました。サンプルコードは以下の様に変更してください。

import Foundation

// オペレーションキューを作る
var queue = OperationQueue()

// オペレーションキュー上で処理させる
queue.addOperation { () -> Void in
    // ... 省略 ...
    for i in 1 ... 10 {
        // ... 省略 ...
        // このキューのスレッドを1秒間スリープ
        Thread.sleep(forTimeInterval: 1)
    }
}

// メインスレッドを15秒間スリープ
Thread.sleep(forTimeInterval: 15)

P.759, メインオペレーションキューを取得するには

「mainQueue」メソッドは「main」プロパティに変更されました。

class var main: OperationQueue { get }

SECTION 240

P.760-761, オペレーションキューにオペレーションを追加する

「addOperationWithBlock」メソッドは「addOperation」メソッドに変更されました。

func addOperation(_ block: @escaping () -> Void)

サンプルコードは以下の様に変更してください。

import Foundation

// オペレーションキューを作る
var queue = OperationQueue()

// オペレーションキュー上で処理させる
queue.addOperation { () -> Void in
    // ... 省略 ...
    for i in 1 ... 10 {
        // ... 省略 ...
        // このキューのスレッドを1秒間スリープ
        Thread.sleep(forTimeInterval: 1)
    }
}

// オペレーションキュー上で処理させる
queue.addOperation { () -> Void in
    var i = 0
    for i in 0 ..< 20 {
        // ... 省略 ...
        // 0.5秒スリープ
        Thread.sleep(forTimeInterval: 0.5)
    }
}

// メインスレッドを15秒間スリープ
Thread.sleep(forTimeInterval: 15)

P.762-764, オペレーションクラスのサブクラスでオペレーションの処理を実装する

「NSOperation」は「Operation」に変更されました。追加するメソッドの定義は次のようになっています。

func addOperation(_ op: Operation)
func addOperations(_ ops: [Operation], waitUntilFinished wait: Bool)

サンプルコードは以下の様に変更してください。

SumOperation.swift

import Foundation

// クラスを定義する
class SumOperation: Operation {
    // ... 省略 ...
    // オペレーションの処理
    override func main() {
        var sum: Int = 0

        for i in minValue ... maxValue {
            // ... 省略 ...

            OperationQueue.main.addOperation({ () -> Void in
                print("\(i): \(sum)")
            })

            // 1秒間スリープする
            Thread.sleep(forTimeInterval: 1)
        }
    }
}

main.swift

import Foundation

// オペレーションキューを作る
var queue = OperationQueue()

// ... 省略 ...

// キューに追加する
queue.addOperations([op1, op2, op3], waitUntilFinished: false)

// 開始日時を取得する
var startDate = Date()

// ランループを取得する
var runLoop = RunLoop.current

// 7秒間ランループを手動で動かす
var isContinue = true
while isContinue {
    autoreleasepool{
        // ランループを手動実行する
        runLoop.run(until: Date(timeIntervalSinceNow: 0.1))

        // 15秒間経過したか?
        var dt = NSDate().timeIntervalSince(startDate)
        // ... 省略 ...
    }
}

SECTION 241

P.765-766, オペレーションキューのオペレーション完了まで待機する

サンプルコードを以下の様に変更してください。

SumOperation.swift

import Foundation

// クラスを定義する
class SumOperation: Operation {
    // ... 省略 ...
    override func main() {
        var sum: Int = 0

        for i in minValue ... maxValue {
            // 加算する
            sum += i

            // 1秒間スリープする
            Thread.sleep(forTimeInterval: 1)
        }

        // 結果を出力する
        print("sum(\(self.minValue)...\(self.maxValue)): \(sum)")
    }
}

main.swift

// ... 省略 ...

// キューに入れたオペレーションが完了するまで待機する
queue.waitUntilAllOperationsAreFinished()

// メッセージを出力
print("completed")

P.767-768, 追加したオペレーションが完了するまで待機する

サンプルコードを以下の様に変更してください。

SumOperation.swift

import Foundation

// クラスを定義する
class SumOperation: Operation {
    // ... 省略 ...
    override func main() {
        var sum: Int = 0

        for i in minValue ... maxValue {
            // 加算する
            sum += i

            // 1秒間スリープする
            Thread.sleep(forTimeInterval: 1)
        }

        // 結果を出力する
        print("sum(\(self.minValue)...\(self.maxValue)): \(sum)")
    }
}

main.swift

import Foundation

// オペレーションキューを作る
var queue = OperationQueue()

// ... 省略 ...

P.768-770, 特定のオペレーションが完了するまで待機する

サンプルコードを以下の様に変更してください。

SumOperation.swift

import Foundation

// クラスを定義する
class SumOperation: Operation {
    // ... 省略 ...
    override func main() {
        var sum: Int = 0

        for i in minValue ... maxValue {
            // 加算する
            sum += i

            // 1秒間スリープする
            Thread.sleep(forTimeInterval: 1)

            // キャンセル状態になっているか?
            if self.isCancelled {
                // キャンセル状態なので中止
                break
            }
        }

        self.result = sum;
    }
}

main.swift

import Foundation

// オペレーションキューを作る
var queue = OperationQueue()

// ... 省略 ...

SECTION 242

P.771-773, オペレーションキューのオペレーションをキャンセルする

「cancelled」プロパティは「isCancelled」プロパティに変更されています。

var isCancelled: Bool { get }

サンプルコードは以下の様に変更してください。

SumOperation.swift

import Foundation

// クラスを定義する
class SumOperation: Operation {
    // ... 省略 ...
    override func main() {
        var sum: Int = 0

        for i in minValue ... maxValue {
            // 加算する
            sum += i

            // 1秒間スリープする
            Thread.sleep(forTimeInterval: 1)

            // キャンセル状態になっているか?
            if self.isCancelled {
                // キャンセル状態なので中止
                break
            }
        }

        self.result = sum;
    }
}

main.swift

import Foundation

// オペレーションキューを作る
var queue = OperationQueue()

// ... 省略 ...

// 2秒間スリープする
Thread.sleep(forTimeInterval: 2)

// ... 省略 ...

P.773-775, 特定のオペレーションをキャンセルするには

サンプルコードを以下の様に変更してください。

SumOperation.swift

import Foundation

// クラスを定義する
class SumOperation: Operation {
    // ... 省略 ...
    override func main() {
        var sum: Int = 0

        for i in minValue ... maxValue {
            // 加算する
            sum += i

            // 1秒間スリープする
            Thread.sleep(forTimeInterval: 1)

            // キャンセル状態になっているか?
            if self.isCancelled {
                // キャンセル状態なので中止
                break
            }
        }

        self.result = sum;
    }
}

main.swift

import Foundation

// オペレーションキューを作る
var queue = OperationQueue()

// ... 省略 ...

// 2秒間スリープする
Thread.sleep(forTimeInterval: 2)

// ... 省略 ...

SECTION 243

P.776-777, オペレーションキューで並列実行されるオペレーション数を制限する

サンプルコードを以下の様に変更してください。

SumOperation.swift

import Foundation

// クラスを定義する
class SumOperation: Operation {
    // ... 省略 ...
    override func main() {
        var sum: Int = 0

        for i in minValue ... maxValue {
            // 加算する
            sum += i

            // 1秒間スリープする
            Thread.sleep(forTimeInterval: 1)
        }

        // 結果を出力する
        print("sum(\(self.minValue)...\(self.maxValue): \(sum))")
    }
}

main.swift

import Foundation

// オペレーションキューを作る
var queue = OperationQueue()

// ... 省略 ...

SECTION 244

P.778, スレッドをスリープさせる

「sleepForTimeInterval」メソッドは「sleep」メソッドに変更されました。

class func sleep(forTimeInterval ti: TimeInterval)

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// スレッド5秒間スリープさせる
Thread.sleep(forTimeInterval: 5)

// ... 省略 ...

P.779, 指定した日時までスリープさせるには

「sleepUntilDate」メソッドは「sleep」メソッドに変更されました。

class func sleep(until date: Date)

サンプルコードは以下の様に変更してください。

// ... 省略 ...

// スレッドをスリープさせる
Thread.sleep(until: date as Date)

// ... 省略 ...

SECTION 245

P.780-782, ロックを使って排他制御を行う

サンプルコードを以下の様に変更してください。

main.swift

import Foundation

// オペレーションキューを作成する
var queue = OperationQueue()
var queue2 = OperationQueue()

// 複数のスレッドから同時アクセスするインスタンスを確保する
var calc = Calc()

// 1足すオペレーションを複数確保して、複数スレッドで同時アクセスさせる
for i in 0 ..< 5 {
    queue.addOperation({ () -> Void in
        calc.plus(i: 1)
    })
    queue2.addOperation({ () -> Void in
        calc.plus(i: 1)
    })
}
// ... 省略 ...

P.782, ロックできるまでのタイムアウトを指定するには

「tryLock」メソッドは「try」メソッド、「lockBeforeDate」メソッドは「lock」メソッドに変更されました。

func `try`() -> Bool
func lock(before limit: Date) -> Bool

P.783-784, Objective-Cの「@synchronized」について

サンプルコードを以下の様に変更してください。

main.swift

import Foundation

// オペレーションキューを作成する
var queue = OperationQueue()
var queue2 = OperationQueue()

// 複数のスレッドから同時アクセスするインスタンスを確保する
var calc = Calc()

// 1足すオペレーションを複数確保して、複数スレッドで同時アクセスさせる
for i in 0 ..< 5 {
    queue.addOperation({ () -> Void in
        calc.plus(i: 1)
    })
    queue2.addOperation({ () -> Void in
        calc.plus(i: 1)
    })
}
// ... 省略 ...

SECTION 246

P.785-787, 再帰ロックを使って排他制御を行う

サンプルコードを以下の様に変更してください。

main.swift

import Foundation

// オペレーションキューを作成する
var queue = OperationQueue()
var queue2 = OperationQueue()

// 複数のスレッドから同時アクセスするインスタンスを確保する
var calc = Calc()

// 1足すオペレーションを複数確保して、複数スレッドで同時アクセスさせる
for i in 0 ..< 5 {
    queue.addOperation({ () -> Void in
        calc.plus(i: 1)
    })
    queue2.addOperation({ () -> Void in
        calc.plus(i: 1)
    })
}
// ... 省略 ...

SECTION 247

P.788-790, コンディションロックを使って排他制御を行う

「unlockWithCondition」メソッドは「unlock」メソッド、「lockWhenCondition」メソッドは「lock」メソッド、「tryLockWhenCondition」メソッドは「tryLock」メソッドに変更されました。

func unlock(withCondition condition: Int)

func lock(whenCondition condition: Int)
func lock(whenCondition condition: Int, before limit: Date) -> Bool
func tryLock(whenCondition condition: Int) -> Bool

サンプルコードを以下の様に変更してください。

Calc.swift

import Foundation

class Calc: NSObject {
    // ... 省略 ...

    // 計算処理
    func calc() -> Int {

        // ロックする
        self.lockObj.lock()

        var n: Int = 0

        for i in 1 ... 5 {
            n += i
            Thread.sleep(forTimeInterval: 1)
        }

        // 状態変数を1に変更してロック解除する
        self.lockObj.unlock(withCondition: 1)

        return n
    }
}

main.swift

import Foundation

// オペレーションキューを作成する
var queue = OperationQueue()

// 複数のスレッドからアクセスするインスタンスを確保する
var calc = Calc()

// 計算処理を別スレッドで開始する
queue.addOperation { () -> Void in
    calc.result = calc.calc()
}

// 1秒スリープさせて、計算処理が先に動くようにする
Thread.sleep(forTimeInterval: 1)

// 状態変数の値が1になるまで待機する
print("Wait")
calc.lockObj.lock(whenCondition: 1)

// 結果を出力する
print("Result = \(calc.result)")

// ロック解除
calc.lockObj.unlock()

SECTION 248

P.791, ディスパッチキューを作成する

「DispatchQueue」を使用するように変更します。「dispatch_queue_create」の代わりに「DispatchQueue」のインスタンスを確保します。

init(__label label: UnsafePointer<Int8>?, attr: __OS_dispatch_queue_attr?)

サンプルコードは以下の様に変更してください。

import Foundation

// 無名のディスパッチキューを作成する
var queue = DispatchQueue(label: "")

// 名前付きのディスパッチキューを作成する
var queue2 = DispatchQueue(label: "MyDispatchQueue")

// コンソールに出力する
print(queue)
print(queue2)

P.792-793, メインキューやグローバルキューを取得するには

以下のようなプロパティとメソッドが定義されました。これらを使用します。

class var main: DispatchQueue { get }
class func global(qos: DispatchQoS.QoSClass = default) -> DispatchQueue

SECTION 249

P.794, ディスパッチキューで同期実行する

「dispatch_sync」関数は「DispatchQueue.sync」メソッドに変更されました。

func sync(execute block: () -> Void)

サンプルコードは以下の様に変更してください。

import Foundation

// 無名のディスパッチキューを作成する
var queue = DispatchQueue(label: "")

for i in 0 ... 5 {
    // キューに同期実行する処理を追加する
    queue.sync(execute: { () -> Void in
        // コンソールに値を出力する
        print("i = \(i)")
    })
}

SECTION 250

P.795-796, ディスパッチキューで非同期実行する

「dispatch_async」関数は「DispatchQueue.async」メソッドに変更されました。

func async(group: DispatchGroup? = default, qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, execute work: @escaping () -> Void)

サンプルコードは以下の様に変更してください。

import Foundation

// コンカレントキューを作成する
var queue = DispatchQueue(label: "", attributes: .concurrent)

// シリアルキューを作成する
var serialQueue = DispatchQueue(label: "", attributes: [])

for i in 0 ... 5 {
    // キューに同期実行する処理を追加する
    queue.async(execute: { () -> Void in
        // 乱数でスリープ時間をランダムにする
        Thread.sleep(forTimeInterval: TimeInterval(arc4random() % 3))

        // 出力する文字列を作る
        var str = "i = \(i)"

        /// コンソールへの出力は呼び出し順にするためシリアルキューで行う
        serialQueue.async(execute: { () -> Void in
            print(str)
        })
    })
}

// キューに追加した処理が完了するまで待機するためスリープする
Thread.sleep(forTimeInterval: 15)

P.796, 乱数について

「random」関数を使った乱数生成は出来なくなりました。代わりに「arc4random」関数や「arc4random_uniform」関数を使用します。

public func arc4random() -> UInt32
public func arc4random_uniform(_ __upper_bound: UInt32) -> UInt32

P.797-798, 特定のタイミングでコンカレントキュー上の処理の完了を待機するには

「dispatch_barrier_sync」関数と「dispatch_barrier_async」関数は削除され、代わりに、「sync」メソッドと「async」メソッドの引数「flags」に「.barrier」を指定するように変更されました。サンプルコードは以下の様に変更してください。

import Foundation

// コンカレントキューを作成する
var queue = DispatchQueue(label: "", attributes: .concurrent)

// シリアルキューを作成する
var serialQueue = DispatchQueue(label: "", attributes: [])

for i in 0 ... 5 {
    // キューに同期実行する処理を追加する
    queue.async(execute: { () -> Void in
        // 乱数でスリープ時間をランダムにする
        Thread.sleep(forTimeInterval: TimeInterval(arc4random() % 3))

        // 出力する文字列を作る
        var str = "i = \(i)"

        /// コンソールへの出力は呼び出し順にするためシリアルキューで行う
        serialQueue.async(execute: { () -> Void in
            print(str)
        })
    })
}

// 追加済みの処理完了後にコンソールに出力する
queue.sync(flags: .barrier, execute: { () -> Void in
    serialQueue.sync(execute: { () -> Void in
        print("END")
    })
})

SECTION 251

P.799-800, ディスパッチキューで遅延実行する

「dispatch_after」関数は「DispatchQueue.asyncAfter」メソッドに変更され、「dispatch_time」関数は「DispatchTime」を使って値を作るように変更してください。

func asyncAfter(deadline: DispatchTime, qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, execute work: @escaping () -> Void)

サンプルコードは以下の様に変更してください。

import Foundation

// ディスパッチキューを作成する
var queue = DispatchQueue(label: "", attributes: [])

// コンソールに現在日時を出力
print(Date())

// 2秒後にコンソールに出力する
var dt = DispatchTime.now() + Double(Int64(NSEC_PER_SEC * 2)) / Double(NSEC_PER_SEC)
queue.asyncAfter(deadline: dt) { () -> Void in
    print(Date())
}

// 完了するまで待機するために少しスリープ
Thread.sleep(forTimeInterval: 5)

SECTION 252

「dispatch_once」関数は使えなくなりました。