80
EZNET 熊友宏 http://eznet.jp/ 2015.07.25 @ カジュアル Swift 勉強会 #1 Swift 2.0 で変わったところ Swift カジュアルプログラミング (前編)

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

Embed Size (px)

Citation preview

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

EZ-‐‑‒NET  熊⾕谷友宏  http://ez-‐‑‒net.jp/

2015.07.25  @  カジュアル  Swift  勉強会  #1

Swift  2.0  で変わったところSwift  カジュアルプログラミング

(前編)

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

熊谷友宏EZ-NET http://ez-net.jp/ @es_kumagai

Xcode 5 徹底解説

IP Phone 音でダイヤル 音で再配達ゴッドいつもの電卓 with 割勘ウォッチ

MOSA

勉強会開催 #yidev 横浜 iPhone 開発者勉強会カジュアル Swift 勉強会 @ 青葉台

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

新言語 Swift 登場 2014.06.02 @ WWDC 2014

Swift 2.0 登場 2015.06.08 @ WWDC 2015

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

大幅な仕様変更

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

そこで

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

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

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

制御構文1/4

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

guard

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

▶ 以降、条件式を満たすことを保証 ▶ 満たさなければスコープの終了を保証 ▶ 早期 Exit

guard《予防線》

guard expression else {

// 条件を満たさない場合は// ここでスコープを抜ける実装を書く

}

// これ以降は条件を満たしていることを保証

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

早期 Exit を保証guard

guard value != 0 else {

// ここでスコープを抜けるコードを書かないとエラー

} 'guard' body may not fall through, consider using 'return' or 'break' to exit the scope

▶ return ▶ break ▶ continue ▶ fatalError

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

変数が 0 以外であることを保証guard

guard value2 != 0 else {

// 0 の場合は結果を 0 とみなす return 0

}

// これ以降は 0 ではないこと前提で記載できる return value1 / value2

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

変数が nil でないことを保証guard

guard let value = optional else {

// nil の場合は結果を .Unknown とする return .Unknown

}

// これ以降は value を使ってコーディングできる let data = calculate(value)

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

複雑な条件を指定して保証guard

guard let path = getPath() where path.hasPrefix("/Volumes") else {

fatalError() }

// 変数 path が "/Volumes" で始まることを保証

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

defer

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

▶ スコープを抜ける直前に実行する ▶ defer の内部で直前までに宣言された変数が使える

defer《繰り延べ》

defer {

// スコープを抜ける寸前に実行したい処理を記載

}

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

スコープを抜ける直前に実行defer

var handle:Handle = File.open(path)

// 最後に必ずリソースを閉じる defer { handle.close() }

// スコープを抜けない限りはリソースを使える string.writeTo(&handle)

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

複数の defer を実行defer

defer { print(1) } defer { print(2) }

▶ 最後にスタック順に実行2 → 1

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

入れ子にして defer を実行defer

defer { defer { print(1) } print(2) }

▶ defer を抜ける直前で実行2 → 1

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

複数呼び出しと入れ子の複合defer

defer { defer { print(1) } print(2) } defer { print(3) }

▶ ルールどおりの順序3 → 2 → 1

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

repeat-while

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

▶ ブロックを実行し、最後に条件判定 ▶ 従前の do-while 構文 ▶ 条件式は repeat ブロックの外の扱い

repeat-while《繰り返し》

repeat {

// 処理を書く// この処理を実行後に条件判定

} while expression

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

実行後に条件判定repeat-while

var count = 100

repeat {

// 先にブロックを実行 --count

} while count > 0 // ブロックを抜けて条件判定

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

スコープ内の変数は使えないrepeat-while

let value = 100

repeat {

// while 条件式はスコープの外 let condition = array.contains(value)

} while condition // repeat 内の変数は使えない

Use of unresolved identifier 'condition'

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

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

上⼿手な

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

do-catch

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

▶ エラーハンドリング専用構文 ▶ 投げられた ErrorType を捕捉 ▶ ErrorType は列挙型または NSError

do-catch《エラーハンドリング》

do {

// エラーが発生する可能性のあるコードを記載

} catch {

// ここでエラー処理を行う }

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

エラーの発生と捕捉do-catch

do {

// エラーが発生するポイントで try を明記 var handle = try File.open(path)

// エラーがなければスコープ内の処理を続行

} catch { // エラー発生時のみ実行// ErrorType 型の error 変数を参照可能

print(error) }

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

Error Handling2/4

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

Error Handling

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

エラーの定義方法Error Handling

// 列挙型でエラーを定義 enum FileOperationError : ErrorType {

case FailedToOpen case NotPermitted(String) }

▶ 列挙型を ErrorType に準拠 ▶ 列挙型がエラードメイン ▶ 列挙子で関連するエラーを定義する

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

エラーの送出方法Error Handling

// 列挙子を指定してエラー送信 throw FileOperationError.FailedToOpen

// NSError でエラーを送信 throw NSError(domain: NSInvalidArgumentException, code: 0, userInfo: nil)

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

エラーを詳しく捕捉Error Handling

do {

var handle = try File.open(path)

} catch FileOperationError.FailedToOpen {

// エラーの種類を明記して捕捉

} catch { // すべてのエラーの捕捉も必須

}

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

値付きのエラーを捕捉Error Handling

do {

var handle = try File.open(path)

} catch FileOperationError .NotPermitted(let reason) {

// 列挙子に添えられた値を取り出して使える

} catch { // すべてのエラーの捕捉も必須

}

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

エラーを大雑把に捕捉(詳細を変数で捕捉)Error Handling

do {

var handle = try File.open(path)

} catch let error as FileOperationError {

// 列挙型全体で捕捉

} catch { // すべてのエラーの捕捉も必須

}

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

エラーを大雑把に捕捉(詳細を破棄)Error Handling

do {

var handle = try File.open(path)

} catch is FileOperationError {

// 列挙型全体で捕捉

} catch { // すべてのエラーの捕捉も必須

}

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

スコープ内で投げたエラーも捕捉可能Error Handling

do {

// スコープ内で明示的に投げたエラーも捕捉可能 throw FileOperationError.FailedToOpen

} catch FileOperationError.FailedToOpen { // エラー処理が実行される

}

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

NSError Handing

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

ErrorType は NSError にキャスト可能NSError Handling

let error = FileOperationError.FailedToOpen as NSError

▶ Error Domain は列挙型名 ▶ Error Code は 0 ▶ Description は “The operation couldn’t be completed. (…)”

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

捕捉時に NSError に変換可能NSError Handling

do {

var handle = try File.open(path)

} catch let error as NSError { // NSError と一緒に扱える

print(error.localizedDescription) }

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

エラーの扱い

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

エラーが起こり得ないならエラーの扱い

do {

var handle = try! File.open(path)

} catch {

}

▶ エラーが起こり得ないなら try! ▶ do-catch が不要 ▶ もしエラーが発生すると強制終了

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

呼び出し元にエラー処理を委ねるエラーの扱い

// 引数リストの次に throws を記載 func execute() throws -> String {

// 捕捉しないエラーを呼び出し元へ throw する var handle = try File.open(path)

}

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

エラーの一部を呼び出し元に委ねるエラーの扱い

func execute() throws -> String {

// エラーの一部を捕捉する do {

var handle = try File.open(path)

} catch FileOperationError.NotPermitted {

}

// 捕捉しなかったエラーは呼び出し元に委ねる }

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

引数でエラーを発生するかを決めるエラーの扱い

// エラーが起こり得る関数を引数にとり// 関数リストの後に rethrows を明記 func execute(f:() throws -> Void) rethrows -> String { try f()

// 受け取った関数以外でエラーは発生できない }

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

引数でエラーを発生するかを決めるエラーの扱い

// エラーが起こり得る関数を引数にとり// 関数リストの後に rethrows を明記 func execute(f:() throws -> Void) rethrows -> String { try f()

// 受け取った関数以外でエラーは発生できない throw FileOperationError.FailedToOpen

}

'rethrows' function may only throw by calling a parameter function

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

引数でエラーが発生するかが決まるエラーの扱い

// エラーが発生するかもしれない関数を渡せる // その場合は try が必要になる try execute { () throws -> Void in

}

// エラーが発生しない関数も渡せる // その場合は try が不要(エラーが起こり得ない) execute { () -> Void in

}

rethrows 指定の関数に限り好きな方を渡せる

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

詳細な条件指定3/4

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

Pattern Matching

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

列挙子を扱う(前提)Pattern Matching

// このような場面を想定したとき enum Platform { case IOS(Double) case OSX(Double) }

let platform = Platform.OSX(10.11)

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

if 文で列挙子を判定Pattern Matching

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

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

列挙子に添えた値を抽出Pattern Matching

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

}

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

オプショナルから値を抽出Pattern Matching

// 意味的には Optional Binding と同等 if case let value? = optional { print(value)

}

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

複数のオプショナルから値を抽出Pattern Matching

// タプルを使ってまとめて変換が可能 if case let (a?, b?, c?) = (optionalA, optionalB, optionalC) {

// すべてが nil でない場合に限り処理される print("\(a), \(b), \(c)")

}

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

値が範囲に含まれるか判定Pattern Matching

// たとえば数値 if case 0 ..< 100 = value {

print("contains")

}

// たとえば文字列 if case "A" ..< "G" = string {

print("contains")

}

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

条件指定

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

if 文に where で条件を添える条件指定

// Swift 1.2 でも使えた記載方法 if let string = optionalString where string.hasSuffix(".png") { }

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

パターンマッチとの併用も可能条件指定

// 列挙子から値を抽出して条件判定 if case let .OSX(version) = platform where version > 10.10 { }

// 複数のオプショナルを展開して条件判定 if case let (a?, b?, c?) = (optionalA, optionalB, optionalC) where a + b == c { }

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

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 { }

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

for でも使える条件指定

// nil 以外の要素で繰り返し let optionals:[Int?]

for case let value? in optionals { }

▶ ループの中で判定しなくて良い ▶ fratMap { $0 } でループさせなくて良い

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

for でも使える条件指定

// nil 以外の繰り返しに条件まで付けられる let optionals:[Int?]

for case let value? in optionals where value > 0 { }

▶ 該当した要素だけが繰り返しの対象に

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

Extension4/4

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

Protocol Extension

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

▶ プロトコルに既定の実装を添える仕組み ▶ 型エイリアスで実装条件を絞れる

Protocol Extension

extension Protocol {

func doSomething() {

// ここに実装を記載できる }

}

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

既定の実装Protocol Extension

extension CollectionType {

var count:Index.Distance { return distance( self.startIndex, self.endIndex) }

}

▶ プロトコルで決められた機能で実装を組み立てる

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

条件付きで拡張Protocol Extension

extension CollectionType where Generator.Element : IntegerType {

var sum:Generator.Element { return self.reduce(0, combine: +) } }

▶ 型エイリアスをプロトコルで縛るとそれを想定した機能が使える

▶ 条件を満たす型だけに実装される

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

複数の条件で縛る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) }

}

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

同じ型であることを明記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) } }

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

自分自身を条件で縛るProtocol Extension

extension CollectionType where Self : Equatable, Self : NillLiteralConvertible {

var isNull:Bool { return self == nil }

}

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

明示的に型で縛るProtocol Extension

extension CollectionType where Generator.Element == String { var lastPathComponents:String { return self.map { $0.lastPathComponent } }

}

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

既定の実装は上書き可能Protocol Extension

extension MyProtocol { var isValid:Bool { return false } }

struct MyStruct : MyProtocol {

var isValid:Bool {

return true }

}採⽤用

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

継承して上書き可能Protocol Extension

protocol MyProtoA { }

protocol MyProtoB : MyProtoA { } extension MyProtoA { func action() -> Int { } } extension MyProtoB { func action() -> Int { } }

採⽤用

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

親を呼ぶ、みたいなことはできないProtocol Extension

extension MyProtoA {

func action() -> Int { } }

extension MyProtoB { func action() -> Int {

return super.action() } }

'super' cannot be used outside of class members

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

キャストで呼び出し先を明記可能Protocol Extension

extension MyProtoA {

func action() -> Int { } } extension MyProtoB { func action() -> Int {

return (self as MyProtoA).action() + 1 } }

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

Type Extension

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

▶ 従来からある型の拡張方法 ▶ Swift 2 からジェネリックパラメータで条件を絞れる

Type Extension

extension Array where Element : IntegerType {

func doSomething() {

} }

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

条件をプロトコルで縛るType Extension

extension Optional where T : SignedNumberType { var negative:Optional { return self.map { -$0 } }

}

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

型では縛れないType Extension

extension Optional where T == String { }

Same-type requirement makes generic parameter 'T' non-generic

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

型の拡張は “既定の実装” ではないType Extension

extension MyStruct { var isValid:Bool { return false } }

struct MyStruct {

var isValid:Bool {

return true }

}

おさらい

Invalid redeclaration of 'isValid'

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

後編Coming Soon ?

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

Swift 2.0 で変わったところ(前編)

▶ 制御構文 ▶ Error Handling ▶ 詳細な条件指定 ▶ Extension