Skip to main content
My Sweet Swift
Agenda 
• Generics 
• Enumeration 
• Optional 
• Appendix
Agenda 
• Generics 
• Enumeration 
• Optional 
• Appendix 
}準備 
本題
Generics
Generics 
• 型をパラメータにとる関数・データ構造 
• 型情報を保ったまま、複数の型に同時に対応 
できる 
• とは?
例: 入力をそのまま返す関数 
func identity(input: Int) -> Int { 
return input 
} 
! 
let number = identity(42) // Int 
let string = identity("Lorem ipusm") // error
例: 入力をそのまま返す関数 
func identity(input: Any) -> Any { 
return input 
} 
! 
let number = identity(42) // Any 
let string = identity("Lorem ipsum") // Any 
! 
number * 2 // error 
string + string // error
例: 入力をそのまま返す関数 
func identity<T>(input: T) -> T { 
return input 
} 
! 
let number = identity(42) // Int 
let string = identity("Lorem ipsum") // String 
! 
number * 2 
string + string
例: map 
x 
f 
"(x)" 
func f(x: Int) -> String { 
return "(x)" 
}
例: map 
x [1, 2, 3] 
f 
"(x)"
例: map 
x [1, 2, 3] 
f 
"(x)" ["1", "2", "3"]
例: map 
x [1, 2, 3] 
f 
"(x)" ["1", "2", "3"] 
map([Int], Int -> String) -> [String]
例: map 
func f(x: Int) -> String { 
return "(x)" 
} 
! 
func map(xs: [Int], f: Int -> String) -> [String] { 
var ys = [String]() 
for x in xs { 
ys.append(f(x)) 
} 
return ys 
} 
! 
map([1, 2, 3], f) // ["1", "2", “3"] 
map([1, 2, 3], { "($0)" }) // ["1", "2", "3"]
例: map 
Int [Int] 
f 
String [String] 
map([Int], Int -> String) -> [String]
例: map 
T [T] 
T -> U 
U [U] 
map([T], T -> U) -> [U]
例: map 
func map<T, U>(xs: [T], f: T -> U) -> [U] { 
var ys = [U]() 
for x in xs { 
ys.append(f(x)) 
} 
return ys 
} 
! 
// [Int] -> [String] 
map([1, 2, 3], { "($0)" }) // ["1", "2", "3"] 
// [Int] -> [Double] 
map([1, 2, 3], { $0 * 2.0 }) // [2.0, 4.0, 6.0] 
// [Double] -> [CGRect] 
map([1, 2, 3], { CGRect(x: $0, y: $0, width: 100.0, height: 100.0) })
クラスの例: Stack 
class Stack<T> { 
private var array = [T]() 
func push(item: T) { 
array.append(item) 
} 
func pop() -> T { 
return array.removeLast() 
} 
} 
! 
let stack = Stack<Int>() 
stack.push(1) 
stack.push(2) 
stack.push(3) 
stack.pop() // 3 
stack.pop() // 2 
stack.pop() // 1
Enumerations
Enums 
enum BloodType { 
case A, B, O, AB 
} 
! 
struct Person { 
var bloodType: BloodType 
} 
! 
var p = Person(bloodType: BloodType.A) 
var q = Person(bloodType: .A) 
q.bloodType = .AB
Enums 
• ObjCのEnumと違って、「値」を持たない 
• ex. 東西南北に整数を割り当てる意味? 
• 従来通りに値を持たせることもできる 
• 文字列もOK
…with associated values 
/// ダイアログのUI要素を指定するenum。 
enum DialogItem { 
case TextButton(title: String, identifier: String) 
case GrayButton(title: String, identifier: String) 
case Text(String) 
case Title(String) 
case Margin(CGFloat) 
case Group([DialogItem]) 
} 
! 
let item1 = DialogItem.Margin(20) 
let item2 = DialogItem.Text("String")
Associated Values 
• enumの各状態に値を紐づけることができる 
• 型が違っていてもいい 
• 単なる列挙というよりは、「複数の型のどれ 
か」を表す型になる
Switchで値を展開 
switch item { 
case let .Title(title): 
println("Title: (title)") 
case let .Text(text): 
println("Text: (text)") 
case let .TextButton(title: title, identifier: identifier): 
/// 
case let .GrayButton(title: title, identifier: identifier): 
/// 
case let .Group(subitems): 
/// 
default: break 
}
例: DialogViewController 
let items: [DialogViewController.DialogItem] = [ 
.Title("ダイアログ"), 
.Text("表示要素を配列で渡すだけで、自在にダイアログを作ることができます。"), 
.TextButton(title: "ボタン", identifier: "button1"), 
.Margin(60), 
.Group([ 
.Group([.Text("二段組み"), .Text("にも")]), 
.Group([.Text("対応"), .Text("(たぶん)")]) 
]), 
.Group([ 
.TextButton(title: "ボタン", identifier: "button2"), 
.GrayButton(title: "ボタン", identifier: "button3"), 
.TextButton(title: "ボタン", identifier: "button4") 
]) 
] 
let dialog = DialogViewController(items: items, callback: nil) 
presentViewController(dialog, animated: true, completion: nil)
簡単な例: Failable 
• 「失敗するかもしれない」結果を記述する 
• 失敗すればFailed、成功すればSucceeded 
• 成功した場合は結果をAssociated Valueに持 
つ
例: Failable<T> 
enum Failable<T> { 
case Succeeded(T) // 成功したときの値 
case Failed // 失敗フラグ 
init(_ value: T) { 
self = .Succeeded(value) 
} 
}
例: Failable<T> 
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 
func failableHalve(x: Int) -> Failable<Int> { 
if x % 2 == 0 { 
return .Succeeded(x / 2) 
} else { 
return .Failed 
} 
} 
! 
switch failableHalve(12) { 
case let .Succeeded(r): 
println("Answer: (r)") 
default: 
println("Odd Number") 
}
それって 
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 
func failableHalve(x: Int) -> Optional<Int> { 
if x % 2 == 0 { 
return .Some(x / 2) 
} else { 
return .None 
} 
} 
! 
switch failableHalve(12) { 
case let .Some(r): 
println("Answer: (r)") 
default: 
println("Odd Number") 
}
Optionalなのでは? 
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 
func failableHalve(x: Int) -> Int? { 
if x % 2 == 0 { 
return x / 2 
} else { 
return nil 
} 
} 
!! 
if let r = failableHalve(12) { 
println("Answer: (r)") 
} else { 
println("Odd Number") 
}
Optional
太古よりnullは人々を苦しめてきた
Optional以前 
• オブジェクトとはポインタである 
• 特別なアドレス(多くの場合0)をNULLと呼 
び、そこを指すポインタを「無効なオブジェ 
クト」として扱う
問題点 
• NULLを無効な値だと知っているのは実行中のプ 
ログラムとプログラマだけ 
• コンパイラには他のポインタ値と区別できない 
• →実行時に落ちる 
• 予期せぬNULLが紛れ込まないように「気をつけ 
る」「確認する」ことしかできなかった
Optionalのいいところ 
• 「無効な値」という概念を型にしたことで、 
意味論ではなく構文論として扱える 
• 無効な値を扱う操作が「書けない」文法
Optional<T> 
enum Optional<T> : Reflectable, NilLiteralConvertible { 
case None 
case Some(T) 
! 
/// Construct a `nil` instance. 
init() 
! 
/// Construct a non- `nil` instance that stores `some`. 
init(_ some: T) 
! 
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`. 
func map<U>(f: (T) -> U) -> U? 
! 
/// Returns a mirror that reflects `self`. 
func getMirror() -> MirrorType 
! 
/// Create an instance initialized with `nil`. 
init(nilLiteral: ()) 
}
Optional<T> 
• 実体はGeneric Enum 
• 実はちょっと嘘で、特別扱いを受けている 
• cf. http://qiita.com/koher/items/ 
5dd6ce7427e7ecff4249 
• (Failable<T>と同じように)箱です
Optional as 箱 
• 「Tかもしれない」ではなく、「Tの入る箱」 
• 値に触るためには箱を開ける必要がある 
• binding/coalescing/unwrapping 
• 箱を開けずに操作する方法もある 
• mapping/chaining
Optional Binding 
var optionalInt: Int? 
! 
if let int = optionalInt { // int: Int 
println("optionalInt was (int)") 
} else { 
println("optionalInt was nil") 
} 
! 
var array = [1, 2, 3, 4] 
while let item = array.last { // item: Int 
println("(item)") 
array.removeLast() 
}
箱を開ける: Optional Binding 
• 値があればtrueに評価されつつ中身を変数に 
束縛(bind)してくれる 
• 一度に一個しかbindできないのは多少不便
Optional Coalescing 
optionalInt ?? 3 
! 
// ↓と等価: 
optionalInt != nil ? optionalInt! : 3 
! 
// あるいは: 
func coalesce<T>(lhs: T?, rhs: @autoclosure () -> T) -> T { 
if let lhs = lhs { 
return lhs 
} else { 
return rhs() 
} 
} 
coalesce(optionalInt, 3)
箱を開ける: Optional Coalescing 
• 開けられたら開ける 
• 開けられなかったら開けない 
• かわりにデフォルト値を返す
無理矢理開ける: Forced Unwrapping 
optionalInt! 
• 値があればそれが返るが、なければ落ちる 
• 落ちる可能性があるので使うべきではない 
• 安全が保証できるなら構わないが……
箱から出さずに進める方法 
• Optional mapping 
• Optional chaining
Optional Mapping 
/// 3倍する関数 
func triple(x: Int) -> Int { 
return x * 3 
} 
! 
optionalInt = 2 
// 以下はすべて.Some 6 
optionalInt.map(triple) 
map(optionalInt, triple) 
optionalInt.map({ $0 * 3 })
箱を開けない: Optional Mapping 
• 箱の中から別の箱の中へ 
• 値があればそれを移して別の箱(Optional) 
を作る 
• nilならばnilを返す
Optional Mapping 
T 
U 
T -> U 
T? 
U? 
map(T?, T -> U) -> U?
Optional Chaining 
class A { 
var b: B? 
} 
! 
class B { 
var c: C? 
} 
! 
class C { 
var i: Int = 1 
} 
var a: A? = A() 
// a.b.c.iにアクセスしたい
Optional Chaining 
var a: A? 
! 
if let a = a { 
if let b = a.b { 
if let c = b.c { 
println("We finally find (c.i)!") 
} 
} 
}
Optional Chaining 
var a: A? 
! 
if let i = a?.b?.c?.i { 
println("Optional chaining makes (i)t easy.") 
}
箱を開けない: Optional Chaining 
• 失敗するかもしれない呼び出しを連鎖できる 
• 失敗すればその先には進まずnil
Optional Chaining 
a?.b?.c?.i 
A? 
aはA?型の変数
× 
Optional Chaining 
a.b 
A? 
A?型にbというメンバはない
Optional Chaining 
a?.b?.c?.i 
A? 
a?.bという形にする
Optional Chaining 
a?.b?.c?.i 
A() 
or 
nil 
aはnilかSomeのどちらか
Optional Chaining 
a?.b?.c?.i 
A() 
B? 
or 
nil 
Someならばbに触れる
Optional Chaining 
a?.b?.c?.i 
A() 
B? 
or 
nil nil 
nilならそれで終わり
Optional Chaining 
a?.b?.c?.i 
A() 
B? 
or 
nil nil 
bはB?型の変数
Optional Chaining 
a?.b?.c?.i 
A() 
B() 
C? 
or 
or 
nil nil 
nil 
同じように分岐
Optional Chaining 
a?.b?.c?.i 
A() 
B() 
C() 
7 
or 
or 
or 
nil nil 
nil 
nil 
以下同文
書き直してみる 
extension Optional { 
func chain<U>(f: T -> U?) -> U? { 
if let s = self { 
return f(s) 
} else { 
return nil 
} 
} 
} 
! 
if let i = a.chain({ $0.b }).chain({ $0.c }).chain({ $0.i }) { 
println("(i)") 
} 
! 
// (正確には↓だが説明は省略(結果は等しくなる)) 
// let k = a.chain({ $0.b.chain({ $0.c.chain({ $0.i }) }) })
なぜ書き直したの? 
• メンバ関数以外にも使えるようにしたい 
• これが今日の主役です
Failable Halve 
Int Int? 
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 
func failableHalve(x: Int) -> Int? { 
if x % 2 == 0 { 
return x / 2 
} else { 
return nil 
} 
} 
! 
if let a = failableHalve(x) { 
println("Halve((x)) = (a)") 
} else { 
println("Failed") 
}
Failable Halve Again 
Int Int? 
if let a = failableHalve(x) { 
if let b = failableHalve(a) { 
println("Halve^2((x)) = (b)") 
} else { 
println("Failed") 
} 
} else { 
println("Failed") 
} 
Int Int?
Failable Halve The 3rd 
Int Int? 
if let a = failableHalve(x) { 
if let b = failableHalve(a) { 
if let c = failableHalve(b) { 
println("Halve^3((x)) = (c)") 
} else { 
println("Failed") 
} 
} else { 
println("Failed") 
} 
} else { 
println("Failed") 
} 
Int Int? Int Int?
Failable Halve Chaining 
Int Int? 
if let a = failableHalve(x).chain(failableHalve).chain(failableHalve) { 
println("Halve^3((x)) = (a)") 
} else { 
println("Failed") 
} 
Int? Int?
Failable Halve Chaining 
Int Int? 
Int? Int? 
24 
failableHalve(24) // Some 12 
failableHalve(24).chain(failableHalve) // Some 6 
failableHalve(24).chain(failableHalve).chain(failableHalve) // Some 3 
failableHalve(24).chain(failableHalve).chain(failableHalve).chain(failableHalve) // nil 
! 
36 
failableHalve(36) // Some 18 
failableHalve(36).chain(failableHalve) // Some 9 
failableHalve(36).chain(failableHalve).chain(failableHalve) // nil 
failableHalve(36).chain(failableHalve).chain(failableHalve).chain(failableHalve) // nil
Optional Chaining 
t: T 
T
Optional Chaining 
T f U? 
f(t): U?
Optional Chaining 
U g V? 
T f U? 
f(t): U?
Optional Chaining 
g 
f V? 
T U? 
f(t).chain(g): V?
Optional Chaining 
g 
V h W? 
f V? 
T U? 
f(t).chain(g): V?
Optional Chaining 
g h W? 
f V? 
T U? 
f(t).chain(g).chain(h): W?
Appendix
Array Mapping 
T [T] 
T -> U 
U [U] 
map([T], T -> U) -> [U]
Optional Mapping 
T 
U 
T -> U 
T? 
U? 
map( T?, T -> U) -> U?
Optional<T>とArray<T> 
• T型の値が入った箱 
• mapを使えば箱の中身だけを写すことができ 
る
Optional as 状況 
• ところで、Optionalは「nilかもしれない」と 
いう状況(context)を表現していた 
• Arrayはどんな状況を表現している? 
• →「値が確定していない」
Array as 状況 
Kyoto
目がさめると京都にいた 
(0, 0) 
Kyoto
歩く 
(0, 1) 
(-1,0) (1, 0) 
(0,-1) 
Kyoto
歩く 
/// 座標 
typealias Position = (Int, Int) 
! 
/// 東西南北のどこかへ歩きます 
func walk(from: Position) -> [Position] { 
let (x, y) = from 
return [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] 
} 
! 
walk((0, 0)) // [(-1, 0), (1, 0), (0, -1), (0, 1)]
さらに歩く 
Kyoto
さらに歩く 
Kyoto
Array Chaining 
T [U] 
U 
[V] 
V [W]
Array Chaining 
extension Array { 
func chain<U>(f: Element -> [U]) -> [U] { 
var ys = [U]() 
for x in self { 
ys += f(x) 
} 
return ys 
} 
} 
! 
walk((0, 0)).chain(walk).chain(walk)
もっと状況を! 
• 「値が非同期で返ってくる」も状況
BFTask 
doHeavyJobAsync1().continueWithBlock { 
(task: BFTask!) -> BFTask in 
let result = task.result as NSString 
self.resultLabel1.text = result 
self.resultLabel2.text = "処理中..." 
return self.doHeavyJobAsync2(result) 
}.continueWithBlock { 
(task: BFTask!) -> BFTask in 
let result = task.result as NSString 
self.resultLabel2.text = result 
self.resultLabel3.text = "処理中..." 
return self.doHeavyJobAsync3(result) 
}.continueWithBlock { 
(task: BFTask!) -> AnyObject! in 
let result = task.result as NSString 
self.resultLabel3.text = result 
return nil 
}
BFTask 
private func doHeavyJobAsync2(prevResult: String) -> BFTask { 
var completionSource = BFTaskCompletionSource() 
// 5秒待ちの処理 
// 実用的には、AFNetworkingのcompletionブロック等でsetResultするイメージ 
Util.delay(5, { 
completionSource.setResult(prevResult + "オワタ") 
}) 
return completionSource.task 
}
Task<T> 
class Task<T: AnyObject> { 
private let task: BFTask 
! 
init(task: BFTask) { 
self.task = task 
} 
var result: T? { 
return task.result as? T 
} 
func chain<U: AnyObject>(f: (T -> Task<U>)) -> Task<U> { 
let newTask = task.continueWithBlock { f($0.result as T).task } 
return Task<U>(task: newTask) 
} 
}
Taskを返す関数 
private func doHeavyJobAsync2(prevResult: NSString) -> Task<NSString> { 
let source = Source<NSString>() 
// 5秒待ちの処理 
// 実用的には、AFNetworkingのcompletionブロック等でsetResultするイメージ 
delay(5, { 
source.setResult(prevResult + "オワタ" as NSString) 
}) 
return source.task 
}
Task Chaining 
T U 
U 
V 
V W 
非同期 
非同期 
非同期
Task Chaining 
func heavyTask1(Void) -> Task<NSString> { 
return delayedTask(5) { 
NSLog("First Task (no params)") 
return "123" as NSString 
} 
} 
! 
func heavyTask2(string: NSString) -> Task<NSNumber> { 
return delayedTask(5) { 
NSLog("Second Task (param: (string))") 
return NSNumber(integer: (string as String).toInt() ?? 0) 
} 
} 
! 
func heavyTask3(number: NSNumber) -> Task<NSNumber> { 
return delayedTask(5) { 
NSLog("Third Task (param: (number))") 
return NSNumber(integer: number.integerValue * 2) 
} 
}
Task Chaining 
NSLog("Start") 
heavyTask1().chain(heavyTask2).chain(heavyTask3) 
NSLog("End") 
2014-11-27 21:15:24.659 MySweetSwift[18362:314049] Start 
2014-11-27 21:15:24.663 MySweetSwift[18362:314049] End 
2014-11-27 21:15:29.663 MySweetSwift[18362:314049] First Task (no params) 
2014-11-27 21:15:35.136 MySweetSwift[18362:314049] Second Task (param: 123) 
2014-11-27 21:15:40.636 MySweetSwift[18362:314049] Third Task (param: 123)
まとめ 
• Optionalはかわいい! 
• ArrayとOptionalは似ている 
• すなわち、箱であり、状況である 
• 非同期処理も同じように見ることができる 
• Optional Chainingのような書きかたができて、そ 
れはBFTaskに似ている
参考文献
以上