Swift 2.0 で変わったところ「前編」 #cswift

175 Views

July 26, 15

スライド概要

2015.07.25 に開催した『カジュアル Swift 勉強会』で、Swift 2.0 での変更点をざっくりと紹介してみました。気づいた全部を紹介するつもりでいたんですけど、思いのほか量が多くてひとまずは「前編」という形で、とりわけ目立つ変更点を取り上げてみます。

※ Docswell での公開に移行する直前の Slideshare での閲覧数は 28,765 でした。

profile-image

正統派趣味人プログラマー。プログラミングとは幼馴染です。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

Swift  カジュアルプログラミング Swift  2.0  で変わったところ (前編) 2015.07.25   @  カジュアル  Swift  勉強会  #1 EZ-‐‑‒NET  熊⾕谷友宏   http://ez-‐‑‒net.jp/

2.

熊谷友宏 EZ-NET http://ez-net.jp/ @es̲kumagai ̶ 勉強会開催 ̶ #yidev 横浜 iPhone 開発者勉強会 カジュアル Swift 勉強会 @ 青葉台 Xcode 5 徹底解説 MOSA IP Phone 音でダイヤル いつもの電卓 with 割勘ウォッチ 音で再配達ゴッド

3.

新言語 Swift 登場 2014.06.02 @ WWDC 2014 Swift 2.0 登場 2015.06.08 @ WWDC 2015

4.

大幅な仕様変更 ?

5.

そこで

6.

Swift 2.0 で変わったところを ざっくり紹介してみる

7.

1/4 制御構文

8.

guard

9.

guard《予防線》 ▶ 以降、条件式を満たすことを保証 ▶ 満たさなければスコープの終了を保証 ▶ 早期 Exit guard expression else { // 条件を満たさない場合は // ここでスコープを抜ける実装を書く } // これ以降は条件を満たしていることを保証

10.

guard 早期 Exit を保証 guard value != 0 else { // ここでスコープを抜けるコードを書かないとエラー } 'guard' body may not fall through, consider using 'return' or 'break' to exit the scope ▶ return ▶ break ▶ continue ▶ fatalError

11.

guard 変数が 0 以外であることを保証 guard value2 != 0 else { // 0 の場合は結果を 0 とみなす } return 0 // これ以降は 0 ではないこと前提で記載できる return value1 / value2

12.

guard 変数が nil でないことを保証 guard let value = optional else { // nil の場合は結果を .Unknown とする } return .Unknown // これ以降は value を使ってコーディングできる let data = calculate(value)

13.

guard 複雑な条件を指定して保証 guard let path = getPath() where path.hasPrefix("/Volumes") else { } fatalError() // 変数 path が "/Volumes" で始まることを保証

14.

defer

15.

defer《繰り延べ》 ▶ スコープを抜ける直前に実行する ▶ defer の内部で 直前までに宣言された変数が使える defer { // スコープを抜ける寸前に実行したい処理を記載 }

16.

defer スコープを抜ける直前に実行 var handle:Handle = File.open(path) // 最後に必ずリソースを閉じる defer { } handle.close() // スコープを抜けない限りはリソースを使える string.writeTo(&handle)

17.

defer 複数の defer を実行 defer { } print(1) defer { } print(2) ▶ 最後にスタック順に実行 2→1

18.

defer 入れ子にして defer を実行 defer { defer { } } print(1) print(2) ▶ defer を抜ける直前で実行 2→1

19.

defer 複数呼び出しと入れ子の複合 defer { defer { } } print(1) print(2) defer { } print(3) ▶ ルールどおりの順序 3→2→1

20.

repeat-while

21.

repeat-while《繰り返し》 ▶ ブロックを実行し、最後に条件判定 ▶ 従前の do-while 構文 ▶ 条件式は repeat ブロックの外の扱い repeat { // 処理を書く // この処理を実行後に条件判定 } while expression

22.

repeat-while 実行後に条件判定 var count = 100 repeat { // 先にブロックを実行 --count } while count > 0 // ブロックを抜けて条件判定

23.

repeat-while スコープ内の変数は使えない let value = 100 repeat { // while 条件式はスコープの外 let condition = array.contains(value) } while condition // repeat 内の変数は使えない Use of unresolved identifier 'condition'

24.

上⼿手な repeat-while の 使いどころが想像できない

25.

do-catch

26.

do-catch《エラーハンドリング》 ▶ エラーハンドリング専用構文 ▶ 投げられた ErrorType を捕捉 ▶ ErrorType は列挙型または NSError do { // エラーが発生する可能性のあるコードを記載 } catch { // ここでエラー処理を行う }

27.

do-catch エラーの発生と捕捉 do { // エラーが発生するポイントで try を明記 var handle = try File.open(path) // エラーがなければスコープ内の処理を続行 } catch { // エラー発生時のみ実行 // ErrorType 型の error 変数を参照可能 } print(error)

28.

2/4 Error Handling

29.

Error Handling

30.

Error Handling エラーの定義方法 // 列挙型でエラーを定義 enum FileOperationError : ErrorType { } case FailedToOpen case NotPermitted(String) ▶ 列挙型を ErrorType に準拠 ▶ 列挙型がエラードメイン ▶ 列挙子で関連するエラーを定義する

31.

Error Handling エラーの送出方法 // 列挙子を指定してエラー送信 throw FileOperationError.FailedToOpen // NSError でエラーを送信 throw NSError(domain: NSInvalidArgumentException, code: 0, userInfo: nil)

32.

Error Handling エラーを詳しく捕捉 do { var handle = try File.open(path) } catch FileOperationError.FailedToOpen { // エラーの種類を明記して捕捉 } catch { // すべてのエラーの捕捉も必須 }

33.

Error Handling 値付きのエラーを捕捉 do { var handle = try File.open(path) } catch FileOperationError .NotPermitted(let reason) { // 列挙子に添えられた値を取り出して使える } catch { // すべてのエラーの捕捉も必須 }

34.

Error Handling エラーを大雑把に捕捉(詳細を変数で捕捉) do { var handle = try File.open(path) } catch let error as FileOperationError { // 列挙型全体で捕捉 } catch { // すべてのエラーの捕捉も必須 }

35.

Error Handling エラーを大雑把に捕捉(詳細を破棄) do { var handle = try File.open(path) } catch is FileOperationError { // 列挙型全体で捕捉 } catch { // すべてのエラーの捕捉も必須 }

36.

Error Handling スコープ内で投げたエラーも捕捉可能 do { // スコープ内で明示的に投げたエラーも捕捉可能 throw FileOperationError.FailedToOpen } catch FileOperationError.FailedToOpen { // エラー処理が実行される }

37.

NSError Handing

38.

NSError Handling ErrorType は NSError にキャスト可能 let error = FileOperationError.FailedToOpen as NSError ▶ Error Domain は列挙型名 ▶ Error Code は 0 ▶ Description は “The operation couldnʼt be completed. (…)”

39.

NSError Handling 捕捉時に NSError に変換可能 do { var handle = try File.open(path) } catch let error as NSError { // NSError と一緒に扱える } print(error.localizedDescription)

40.

エラーの扱い

41.

エラーの扱い エラーが起こり得ないなら do { var handle = try! File.open(path) } catch { } ▶ エラーが起こり得ないなら try! ▶ do-catch が不要 ▶ もしエラーが発生すると強制終了

42.

エラーの扱い 呼び出し元にエラー処理を委ねる // 引数リストの次に throws を記載 func execute() throws -> String { // 捕捉しないエラーを呼び出し元へ throw する var handle = try File.open(path) }

43.

エラーの扱い エラーの一部を呼び出し元に委ねる func execute() throws -> String { // エラーの一部を捕捉する do { var handle = try File.open(path) } catch FileOperationError.NotPermitted { } // 捕捉しなかったエラーは呼び出し元に委ねる }

44.

エラーの扱い 引数でエラーを発生するかを決める // エラーが起こり得る関数を引数にとり // 関数リストの後に rethrows を明記 func execute(f:() throws -> Void) rethrows -> String { try f() // 受け取った関数以外でエラーは発生できない }

45.
[beta]
エラーの扱い

引数でエラーを発生するかを決める
// エラーが起こり得る関数を引数にとり
// 関数リストの後に rethrows を明記

func execute(f:() throws -> Void) rethrows
-> String {
try f()
// 受け取った関数以外でエラーは発生できない

}

throw FileOperationError.FailedToOpen
'rethrows' function may only throw by
calling a parameter function

46.

エラーの扱い 引数でエラーが発生するかが決まる // エラーが発生するかもしれない関数を渡せる // その場合は try が必要になる try execute { () throws -> Void in } // エラーが発生しない関数も渡せる // その場合は try が不要(エラーが起こり得ない) execute { () -> Void in } rethrows 指定の関数に限り好きな方を渡せる

47.

3/4 詳細な条件指定

48.

Pattern Matching

49.

Pattern Matching 列挙子を扱う(前提) // このような場面を想定したとき enum Platform { } case IOS(Double) case OSX(Double) let platform = Platform.OSX(10.11)

50.

Pattern Matching if 文で列挙子を判定 // 列挙子から直接、添えた値を抽出可能 if case .OSX = platform { }

51.

Pattern Matching 列挙子に添えた値を抽出 // 列挙子から直接、添えた値を抽出可能 if case let .OSX(version) = platform { print(version) }

52.

Pattern Matching オプショナルから値を抽出 // 意味的には Optional Binding と同等 if case let value? = optional { print(value) }

53.

Pattern Matching 複数のオプショナルから値を抽出 // タプルを使ってまとめて変換が可能 if case let (a?, b?, c?) = (optionalA, optionalB, optionalC) { // すべてが nil でない場合に限り処理される print("\(a), \(b), \(c)") }

54.

Pattern Matching 値が範囲に含まれるか判定 // たとえば数値 if case 0 ..< 100 = value { print("contains") } // たとえば文字列 if case "A" ..< "G" = string { print("contains") }

55.

条件指定

56.

条件指定 if 文に where で条件を添える // Swift 1.2 でも使えた記載方法 if let string = optionalString where string.hasSuffix(".png") { }

57.

条件指定 パターンマッチとの併用も可能 // 列挙子から値を抽出して条件判定 if case let .OSX(version) = platform where version > 10.10 { } // 複数のオプショナルを展開して条件判定 if case let (a?, b?, c?) = (optionalA, optionalB, optionalC) where a + b == c { }

58.

条件指定 guard でも使える // 列挙子から値を抽出して条件判定 guard case let .OSX(version) = platform where version > 10.10 else { } // 複数のオプショナルを展開して条件判定 guard case let (a?, b?, c?) = (optionalA, optionalB, optionalC) where a + b == c else { }

59.

条件指定 for でも使える // nil 以外の要素で繰り返し let optionals:[Int?] for case let value? in optionals { } ▶ ループの中で判定しなくて良い ▶ fratMap { $0 } でループさせなくて良い

60.

条件指定 for でも使える // nil 以外の繰り返しに条件まで付けられる let optionals:[Int?] for case let value? in optionals where value > 0 { } ▶ 該当した要素だけが繰り返しの対象に

61.

4/4 Extension

62.

Protocol Extension

63.

Protocol Extension ▶ プロトコルに既定の実装を添える仕組み ▶ 型エイリアスで実装条件を絞れる extension Protocol { func doSomething() { // ここに実装を記載できる } }

64.

Protocol Extension 既定の実装 extension CollectionType { var count:Index.Distance { } return distance( self.startIndex, self.endIndex) } ▶ プロトコルで決められた機能で 実装を組み立てる

65.

Protocol Extension 条件付きで拡張 extension CollectionType where Generator.Element : IntegerType { var sum:Generator.Element { } } return self.reduce(0, combine: +) ▶ 型エイリアスをプロトコルで縛ると それを想定した機能が使える ▶ 条件を満たす型だけに実装される

66.
[beta]
Protocol Extension

複数の条件で縛る
extension CollectionType where
Index : Streamable,
Generator.Element : IntegerType {
func printIndexOf<S:OutputStreamType>
(element:Generator.Element,
inout to stream:S) {

}
}

self.indexOf(element)?.writeTo(&stream)

67.

Protocol Extension 同じ型であることを明記 extension CollectionType where Generator.Element : IntegerType, Index.Distance == Generator.Element { var average:Generator.Element { } return self.reduce(0) { $0 + $1 } / self.count var count:Index.Distance { } } return distance( self.startIndex, self.endIndex)

68.

Protocol Extension 自分自身を条件で縛る extension CollectionType where Self : Equatable, Self : NillLiteralConvertible { var isNull:Bool { } } return self == nil

69.

Protocol Extension 明示的に型で縛る extension CollectionType where Generator.Element == String { var lastPathComponents:String { } } return self.map { $0.lastPathComponent }

70.

Protocol Extension 既定の実装は上書き可能 extension MyProtocol { var isValid:Bool { } } return false struct MyStruct : MyProtocol { var isValid:Bool { } } return true 採⽤用

71.

Protocol Extension 継承して上書き可能 protocol MyProtoA { } protocol MyProtoB : MyProtoA { } extension MyProtoA { func action() -> Int { } } extension MyProtoB { func action() -> Int { } 採⽤用 }

72.

Protocol Extension 親を呼ぶ、みたいなことはできない extension MyProtoA { func action() -> Int { } } extension MyProtoB { func action() -> Int { } } return super.action() 'super' cannot be used outside of class members

73.

Protocol Extension キャストで呼び出し先を明記可能 extension MyProtoA { func action() -> Int { } } extension MyProtoB { func action() -> Int { } } return (self as MyProtoA).action() + 1

74.

Type Extension

75.

Type Extension ▶ 従来からある型の拡張方法 ▶ Swift 2 から ジェネリックパラメータで条件を絞れる extension Array where Element : IntegerType { func doSomething() { } }

76.

Type Extension 条件をプロトコルで縛る extension Optional where T : SignedNumberType { var negative:Optional { } } return self.map { -$0 }

77.

Type Extension 型では縛れない extension Optional where T == String { } Same-type requirement makes generic parameter 'T' non-generic

78.

Type Extension 型の拡張は “既定の実装” ではない extension MyStruct { var isValid:Bool { } } おさらい return false struct MyStruct { var isValid:Bool { } } return true Invalid redeclaration of 'isValid'

79.

後編 Coming Soon ?

80.

Swift 2.0 で変わったところ(前編) ▶ 制御構文 ▶ Error Handling ▶ 詳細な条件指定 ▶ Extension