-->

Swift

try、do、catchについて、ちゃんと調べてみた。
C++、C#、Javaなんかであるtry〜catchみたいなものだ。

まず、独自のエラーを列挙で定義する。

enum MyError:ErrorType {
    case Hoge1
    case Hoge2(Int)
}

エラー(例外?)を投げるところをdo囲って、受けるところをcatchで書く。

do {
//    throw MyError.Hoge1
    throw MyError.Hoge2(4)
} catch MyError.Hoge1 {
    print("1.Catched Hoge1")
} catch MyError.Hoge2(let val) {
    print("1.Catched Hoge2(\(val))")
}

MyError.Hoge2みたいにすると、何らかの値を渡すこともできる。

エラーを投げる関数を書いてみる。

// エラーを投げる関数定義
//   戻り値の型の前にthrowsを書いておく
func ThrowFunc() throws -> Int {
    throw MyError.Hoge1
//    return 1
}

戻り値の型の前にtrowsを書いとく必要がある。

エラーを投げる可能性のある関数(throwsが付いているやつ)を呼び出すときは、doで囲って関数名の前にtryを付ける。

do {
    let r = try ThrowFunc()
} catch let err {
    print(err)
}

do〜catchしない場合は、tryのあとに?を付けるか、!を付ける。
細かい説明は、次のソースコードの中に書いといたので省く。

//let r = try ThrowFunc()   // do~catchしてないとコンパイルエラーになる
let r = try? ThrowFunc()    // tryの後に?を付けるとコンパイルエラーにならない。
print(r)    // rはInt?で、ここではnilになっている。(例外が投げられたらnilが代入されると言うことだ)

let r2 = try! ThrowFunc()   // tryの後に!を付けるとコンパイルエラーにならない。
                            // けどr2はInt型なので、この例の場合実行時にエラーになる。
                            // 当たり前だが、エラーが起こらないのが明白な場合のみ使うべきだな。
print(r2)

次にJavaのfinallyにあたる部分はこんな感じだ。
doの括弧内にdeferで後処理を書く。deferはエラーを投げる関数より前に書いておかないといけない。

do {
    defer {
        print("1.後処理")
    }
    let r = try ThrowFunc()
    // ↓ここだとThrowFuncでエラーになったとき、後処理が実行されない。
	// けど、エラーじゃないときは、2.後処理、1.後処理の順で実行される。
//    defer {
//        print("2.後処理")
//    }
} catch MyError.Hoge1 {
    print("2.Catched Hoge1")
} catch {
    print("2.Hoge1以外をキャッチ")
}

deferは、doと組み合わせないといけないわけではなく、スコープを抜けるときに実行されるので次ようなコードもOKだ。

func DeferTest()->Void {
    print("defer test 1")
    defer {
        print("後処理?")
    }
    print("defer test 2")
}

DeferTest()

実行結果は、

defer test 1
defer test 2
後処理?

と表示される。


このエントリーをはてなブックマークに追加

Swift2をよく調べずに、Swift2を試してみようと、とりあえず、前に作ったテキストファイルの内容をソートするxsortをXCode7で開いてい見た。Swift2は、Swift1と互換性がないような変更が行われているらしいので、ここでプロジェクトのコンバートツールが動き出す。素直にXCodeのいいなりにコンバートを進めて完了。ビルドするとエラーが!(>_<)
まっ、そんなうまいこと行くわけがないわな・・・

エラーが出たのはこんなところ。

	var err:NSError? = NSError()
	var s = String(contentsOfFile: (args[i] as String), encoding: NSUTF8StringEncoding, error: &err)

2行目は、イニシャライザはないって言うような、エラーが出ているみたい。とりあえず、2行目を調べて見よう。
2行目は、ファイルをすべてUTF8の文字列として読み込み変数sに代入する処理だ。ヘルプで見ると、

convenience init(contentsOfFile path: String,
        encoding enc: UInt) throws

って、throwsってのが気になるが、こんな感じでいいのかな〜と書いてみる。

        var s = String.init(contentsOfFile: args[i], encoding: NSUTF8StringEncoding)

エラーになった(^^;)
確かどっかでJavaやC#なんかである例外処理みたいのが追加されたって言ってたな〜と言うことで調べてみる。こんな感じになる。

        var s:String;
        do {
            s = try String.init(contentsOfFile: args[i], encoding: NSUTF8StringEncoding)
        } catch let err {
            let errmsg = "Read ERROR(\(args[i]))\n"
            stderr.writeData(errmsg.dataUsingEncoding(NSUTF8StringEncoding)!)
            exit(1)
        }

とりあえずは、throwsがついてる関数は、頭にtryを付けて、do〜catchで例外を捕捉するんだな。
また今度ちゃんと調べよう(^^;)


このエントリーをはてなブックマークに追加

2つの変数が同一インスタンスかどうかは、===と!==で判定する。

class Hoge {
    // プロパティ
    var hoge:Int = 3
}

// インスタンスの生成
var hoge1 = Hoge()
var hoge2 = hoge1

if hoge1 === hoge2 {
    println("同一インスタンスだ")        // 表示される
}
if hoge1 !== hoge2 {
    println("同一インスタンスでない")      // 表示されない
}

このエントリーをはてなブックマークに追加

クラスの基本はこんな感じだ。

class Hoge {
    // プロパティ
    var hoge:Int = 3
    var hoge2:Int
    // ゲッター、セッター
    var hoge3:Int {
        get {
            return hoge2 * 3
        }
        set {
            hoge2 = newValue / 3
        }
    }
    
    // イニシャライザ
    init(hoge2:Int) {
        self.hoge2 = hoge2
    }
    
    // デイニシャライザ
    deinit {
        println("deinit")
    }
    
    // メソッド
    func methodHoge() -> Int {
        return self.hoge
    }
}

// インスタンスの生成
var hoge = Hoge(hoge2:30)   // イニシャライザでは、ラベルが必要なんだな
println(hoge.hoge2)         // 30と表示
hoge.hoge2 = 60
println(hoge.hoge2)         // 60と表示
println(hoge.hoge3)         // hoge3のゲッターが呼ばれるんで
                            // 180と表示
hoge.hoge3 = 30             // hoge3のセッターが呼ばれて、hoge2に10が設定される
println(hoge.hoge2)         // 10と表示

println(hoge.methodHoge())  // 3と表示
hoge = Hoge(hoge2:22)       // ここで最初のインスタンスが破棄されるのでデイニシャライザが実行されて
                            // deinitと表示
println(hoge.hoge2)
println("END")

プロパティ、メソッドは、それぞれ変数の宣言と関数の宣言と同じだ。
プロパティは、C#みたいに取得するときに呼ばれる処理、設定するときに呼ばれる処理が書ける。setを省略するとリードオンリーのプロパティになる。
イニシャライザ、デイニシャライザはC++のコンストラクタ、デストラクタに相当する。


このエントリーをはてなブックマークに追加

for文で全要素にアクセスする方法で追加。
要素番号こみで各要素にアクセする方法だ。

var hoge = ["hoge1", "hoge2", "hoge3"]
for (index, val) in enumerate(hoge) {
    println("hoge[\(index)] = \(val)")
}
// hoge[0] = hoge1
// hoge[1] = hoge2
// hoge[2] = hoge3
// って、表示。

このエントリーをはてなブックマークに追加

↑このページのトップヘ