Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
EZ-‐‑‒NET  熊⾕谷友宏  
http://ez-‐‑‒net.jp/
2015.07.25  
@  カジュアル  Swift  勉強会  #1
Swift  2.0  で変わったところ
Swift  カジュアルプログラミング
(前編)
熊谷友宏
EZ-NET http://ez-net.jp/
@es_kumagai
Xcode 5 徹底解説
IP Phone 音でダイヤル 音で再配達ゴッド
いつもの電卓
with 割勘ウォッチ
MOSA
̶ 勉強会開催 ̶
#yidev 横浜 iPhone 開発者勉強会
カジュアル Swift 勉強会 @ 青葉台
新言語 Swift 登場
2014.06.02 @ WWDC 2014
Swift 2.0 登場
2015.06.08 @ WWDC 2015
大幅な仕様変更
?
そこで
Swift 2.0 で変わったところを
ざっくり紹介してみる
制御構文
1/4
guard
▶ 以降、条件式を満たすことを保証
▶ 満たさなければスコープの終了を保証
▶ 早期 Exit
guard《予防線》
guard expression else {
// 条件を満たさない場合は

// ここでスコープを抜ける実装を書く
}
// これ以降は条件を満たしていることを保証
早期 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
変数が 0 以外であることを保証
guard
guard value2 != 0 else {
// 0 の場合は結果を 0 とみなす
return 0
}
// これ以降は 0 ではないこと前提で記載できる
return value1 / value2
変数が nil でないことを保証
guard
guard let value = optional else {
// nil の場合は結果を .Unknown とする
return .Unknown
}
// これ以降は value を使ってコーディングできる
let data = calculate(value)
複雑な条件を指定して保証
guard
guard let path = getPath()
where path.hasPrefix("/Volumes") else {
fatalError()
}
// 変数 path が "/Volumes" で始まることを保証
defer
▶ スコープを抜ける直前に実行する
▶ defer の内部で

直前までに宣言された変数が使える
defer《繰り延べ》
defer {
// スコープを抜ける寸前に実行したい処理を記載
}
スコープを抜ける直前に実行
defer
var handle:Handle = File.open(path)
// 最後に必ずリソースを閉じる
defer {
handle.close()
}
// スコープを抜けない限りはリソースを使える
string.writeTo(&handle)
複数の defer を実行
defer
defer {
print(1)
}
defer {
print(2)
}
▶ 最後にスタック順に実行

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

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

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

// この処理を実行後に条件判定
} while expression
実行後に条件判定
repeat-while
var count = 100
repeat {
// 先にブロックを実行
--count
} while count > 0 // ブロックを抜けて条件判定
スコープ内の変数は使えない
repeat-while
let value = 100
repeat {
// while 条件式はスコープの外
let condition = array.contains(value)
} while condition // repeat 内の変数は使えない
Use of unresolved identifier 'condition'
repeat-while の
使いどころが想像できない
上⼿手な
do-catch
▶ エラーハンドリング専用構文
▶ 投げられた ErrorType を捕捉
▶ ErrorType は列挙型または NSError
do-catch《エラーハンドリング》
do {
// エラーが発生する可能性のあるコードを記載

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

// ErrorType 型の error 変数を参照可能
print(error)
}
Error Handling
2/4
Error Handling
エラーの定義方法
Error Handling
// 列挙型でエラーを定義
enum FileOperationError : ErrorType {
case FailedToOpen
case NotPermitted(String)
}
▶ 列挙型を ErrorType に準拠
▶ 列挙型がエラードメイン
▶ 列挙子で関連するエラーを定義する
エラーの送出方法
Error Handling
// 列挙子を指定してエラー送信
throw FileOperationError.FailedToOpen
// NSError でエラーを送信
throw NSError(domain:
NSInvalidArgumentException,
code: 0, userInfo: nil)
エラーを詳しく捕捉
Error Handling
do {
var handle = try File.open(path)
} catch FileOperationError.FailedToOpen {
// エラーの種類を明記して捕捉
} catch {
// すべてのエラーの捕捉も必須
}
値付きのエラーを捕捉
Error Handling
do {
var handle = try File.open(path)
} catch FileOperationError
.NotPermitted(let reason) {
// 列挙子に添えられた値を取り出して使える
} catch {
// すべてのエラーの捕捉も必須
}
エラーを大雑把に捕捉(詳細を変数で捕捉)
Error Handling
do {
var handle = try File.open(path)
} catch let error as FileOperationError {
// 列挙型全体で捕捉
} catch {
// すべてのエラーの捕捉も必須
}
エラーを大雑把に捕捉(詳細を破棄)
Error Handling
do {
var handle = try File.open(path)
} catch is FileOperationError {
// 列挙型全体で捕捉
} catch {
// すべてのエラーの捕捉も必須
}
スコープ内で投げたエラーも捕捉可能
Error Handling
do {
// スコープ内で明示的に投げたエラーも捕捉可能
throw FileOperationError.FailedToOpen
} catch FileOperationError.FailedToOpen {
// エラー処理が実行される
}
NSError Handing
ErrorType は NSError にキャスト可能
NSError Handling
let error
= FileOperationError.FailedToOpen as NSError
▶ Error Domain は列挙型名
▶ Error Code は 0
▶ Description は

The operation couldnt be completed. (…)
捕捉時に NSError に変換可能
NSError Handling
do {
var handle = try File.open(path)
} catch let error as NSError {
// NSError と一緒に扱える
print(error.localizedDescription)
}
エラーの扱い
エラーが起こり得ないなら
エラーの扱い
do {
var handle = try! File.open(path)
} catch {
}
▶ エラーが起こり得ないなら try!
▶ do-catch が不要
▶ もしエラーが発生すると強制終了
呼び出し元にエラー処理を委ねる
エラーの扱い
// 引数リストの次に throws を記載
func execute() throws -> String {
// 捕捉しないエラーを呼び出し元へ throw する
var handle = try File.open(path)
}
エラーの一部を呼び出し元に委ねる
エラーの扱い
func execute() throws -> String {
// エラーの一部を捕捉する
do {
var handle = try File.open(path)
}
catch FileOperationError.NotPermitted {
}
// 捕捉しなかったエラーは呼び出し元に委ねる
}
引数でエラーを発生するかを決める
エラーの扱い
// エラーが起こり得る関数を引数にとり

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

// 関数リストの後に rethrows を明記
func execute(f:() throws -> Void) rethrows
-> String {
try f()
// 受け取った関数以外でエラーは発生できない
throw FileOperationError.FailedToOpen
}
'rethrows' function may only throw by
calling a parameter function
引数でエラーが発生するかが決まる
エラーの扱い
// エラーが発生するかもしれない関数を渡せる
// その場合は try が必要になる
try execute { () throws -> Void in
}
// エラーが発生しない関数も渡せる
// その場合は try が不要(エラーが起こり得ない)
execute { () -> Void in
}
rethrows 指定の関数に限り好きな方を渡せる
詳細な条件指定
3/4
Pattern Matching
列挙子を扱う(前提)
Pattern Matching
// このような場面を想定したとき
enum Platform {
case IOS(Double)
case OSX(Double)
}
let platform = Platform.OSX(10.11)
if 文で列挙子を判定
Pattern Matching
// 列挙子から直接、添えた値を抽出可能
if case .OSX = platform {
}
列挙子に添えた値を抽出
Pattern Matching
// 列挙子から直接、添えた値を抽出可能
if case let .OSX(version) = platform {
print(version)
}
オプショナルから値を抽出
Pattern Matching
// 意味的には Optional Binding と同等
if case let value? = optional {
print(value)
}
複数のオプショナルから値を抽出
Pattern Matching
// タプルを使ってまとめて変換が可能
if case let (a?, b?, c?)
= (optionalA, optionalB, optionalC) {
// すべてが nil でない場合に限り処理される
print("(a), (b), (c)")
}
値が範囲に含まれるか判定
Pattern Matching
// たとえば数値
if case 0 ..< 100 = value {
print("contains")
}
// たとえば文字列
if case "A" ..< "G" = string {
print("contains")
}
条件指定
if 文に where で条件を添える
条件指定
// Swift 1.2 でも使えた記載方法
if let string = optionalString
where string.hasSuffix(".png") {
}
パターンマッチとの併用も可能
条件指定
// 列挙子から値を抽出して条件判定
if case let .OSX(version) = platform
where version > 10.10 {
}
// 複数のオプショナルを展開して条件判定
if case let (a?, b?, c?)
= (optionalA, optionalB, optionalC)
where a + b == c {
}
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 {
}
for でも使える
条件指定
// nil 以外の要素で繰り返し
let optionals:[Int?]
for case let value? in optionals {
}
▶ ループの中で判定しなくて良い
▶ fratMap { $0 } でループさせなくて良い
for でも使える
条件指定
// nil 以外の繰り返しに条件まで付けられる
let optionals:[Int?]
for case let value? in optionals
where value > 0 {
}
▶ 該当した要素だけが繰り返しの対象に
Extension
4/4
Protocol Extension
▶ プロトコルに既定の実装を添える仕組み
▶ 型エイリアスで実装条件を絞れる
Protocol Extension
extension Protocol {
func doSomething() {
// ここに実装を記載できる
}
}
既定の実装
Protocol Extension
extension CollectionType {
var count:Index.Distance {
return distance(
self.startIndex, self.endIndex)
}
}
▶ プロトコルで決められた機能で

実装を組み立てる
条件付きで拡張
Protocol Extension
extension CollectionType
where Generator.Element : IntegerType {
var sum:Generator.Element {
return self.reduce(0, combine: +)
}
}
▶ 型エイリアスをプロトコルで縛ると

それを想定した機能が使える
▶ 条件を満たす型だけに実装される
複数の条件で縛る
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)
}
}
同じ型であることを明記
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)
}
}
自分自身を条件で縛る
Protocol Extension
extension CollectionType where
Self : Equatable,
Self : NillLiteralConvertible {
var isNull:Bool {
return self == nil
}
}
明示的に型で縛る
Protocol Extension
extension CollectionType where
Generator.Element == String {
var lastPathComponents:String {
return self.map { $0.lastPathComponent }
}
}
既定の実装は上書き可能
Protocol Extension
extension MyProtocol {
var isValid:Bool {
return false
}
}
struct MyStruct : MyProtocol {
var isValid:Bool {
return true
}
}
採⽤用
継承して上書き可能
Protocol Extension
protocol MyProtoA {
}
protocol MyProtoB : MyProtoA {
}
extension MyProtoA {
func action() -> Int {
}
}
extension MyProtoB {
func action() -> Int {
}
}
採⽤用
親を呼ぶ、みたいなことはできない
Protocol Extension
extension MyProtoA {
func action() -> Int {
}
}
extension MyProtoB {
func action() -> Int {
return super.action()
}
}
'super' cannot be used outside of class members
キャストで呼び出し先を明記可能
Protocol Extension
extension MyProtoA {
func action() -> Int {
}
}
extension MyProtoB {
func action() -> Int {
return (self as MyProtoA).action() + 1
}
}
Type Extension
▶ 従来からある型の拡張方法
▶ Swift 2 から

ジェネリックパラメータで条件を絞れる
Type Extension
extension Array where Element : IntegerType {
func doSomething() {
}
}
条件をプロトコルで縛る
Type Extension
extension Optional where T : SignedNumberType {
var negative:Optional {
return self.map { -$0 }
}
}
型では縛れない
Type Extension
extension Optional where T == String {
}
Same-type requirement makes
generic parameter 'T' non-generic
型の拡張は 既定の実装 ではない
Type Extension
extension MyStruct {
var isValid:Bool {
return false
}
}
struct MyStruct {
var isValid:Bool {
return true
}
}
おさらい
Invalid redeclaration of 'isValid'
後編
Coming Soon ?
Swift 2.0 で変わったところ(前編)
▶ 制御構文
▶ Error Handling
▶ 詳細な条件指定
▶ Extension

More Related Content

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