EZ-NET 熊⾕友宏
http://ez-net.jp/
2016.03.12
第66回 Cocoa 勉強会勉強会
lazy var の特徴を知る
Swift カジュアルプログラミング
Swift 2.1.1
2016.04.02
第6回 カジュアル Swift 勉強会
熊谷友宏
Xcode 5 徹底解説 MOSA
Xcode 5 の全機能を

徹底的に解説した本
OSX/iOS 系の歴史深い

有料会員制の勉強会
紙版は絶版、電子書籍は販売中
Xcode 7 でも役立つはず 法人会員も多数
@es_kumagai
EZ-NET http://ez-net.jp/
書籍 / 登壇
熊谷友宏
横浜 iPhone 開発者勉強会
#yidev
わいわい・ゆるく、iPhone 開発者の

みんなで楽しく過ごすのが目的の会
【 横浜・馬車道 】
カジュアル Swift 勉強会
#cswift
ゆるくみんなで Swift を語らえる場を

作りたくて始めた会
【 横浜・青葉台 】
第6回を 2016-04-02 に開催予定
@es_kumagai
EZ-NET http://ez-net.jp/
勉強会
熊谷友宏
@es_kumagai
EZ-NET http://ez-net.jp/
CodePiece
iOS, OS X, Apple Watch アプリ
ソースコードを Twitter と
Gist に同時投稿できる。
いつもの電卓
計算式も見える電卓アプリ。
watchOS 1 対応
音で再配達ゴッド
簡単操作で
再配達の申し込み。
EZ-NET IP Phone
iPhone でひかり電話を使う。
自宅 LAN からの利用専用
CodePiece for OS X
勉強会を楽しむアプリ
ソースコードを Twitter と Gist に同時投稿できる

勉強会で知見をみんなと共有したい時とかに便利!
できること
#cswift
try! Swift
2016.03.02 - 2016.03.04
try! Swift
2016 初日
try! Swift
2016 二日目
try! Swift
2016 最終日
try! Swift
The most impressive speaker for me ! 😆
HIPSTER SWIFT
★ @noescape
★ @autoclosure
★ inline lazy vars
★ variadic parameters
★ labeled loops
★ type omitting
HIPSTER SWIFT
inline lazy vars
Lazy Variables
初期化を参照時まで遅延できる変数
HIPSTER SWIFT
▶ 値型プロパティを lazy 付きで定義
▶ 右辺で参照時に設定する値を記載
Lazy Variables
class MyClass {
lazy var value: Int = {
return self.calculate()
}()
}
HIPSTER SWIFT
評価式の書式
lazy var value: Int = {
return self.calculate()
}()
これが …
lazy var value: Int = self.calculate()
こう書ける
HOW BEAUTIFUL ...
BUT … SAFE ?
class MyClass {
lazy var value: Int = self.calculate()
}
HIPSTER SWIFT
評価式の書式
var obj: MyClass? = MyClass()
obj.value
obj = nil
循環参照しない
初期化コードで self を使っていても …
DEINIT!
AWESOME !! 🎉
class MyClass {
lazy var value: Int = self.calculate()
}
HIPSTER SWIFT
気になったところ
Super Lazy Vars
オート
クロージャー
強く参照 !
強く参照 !
どういうことだろう…
循環
しない !
Lazy Variables
もっと理解して使いたい
Lazy Variables
▶ 初期値の設定を参照直前まで延期できる
▶ 主に保存型プロパティで使用
概要
// 定義の仕方
class File {
lazy var content: Content
= Content(path: somePath)
}
File
Lazy Variables
初期化タイミング
= Content(path: somePath)
Contents
lazy var
参照
値
instance
Contents
File
Lazy Variables
自身の機能で初期化できる
= Content(path: self.path)
Contents
lazy var
参照
instance
Contents
参照のときは
インスタンス生成済みなので
初期化処理で self も使える
プロパティを自分自身の機能で
初期化したいときに便利 … なもの?
そう単純なものでもなさそう
Lazy Variables
使いどころ?
挙動
Lazy Variables
▶ 参照のときに初期化が行われる
▶ 初期化して保存してすぐ参照する
挙動 1/7 … 初期化のタイミング
class File {
lazy var content: Content = Content(path: somePath)
}
// ここでは content は初期化されない
let file = File()
// ここで初めて content が初期化され、値がプロパティに保持される
let content = file.content
Lazy Variables
▶ 初回参照時に値が設定される
▶ 以降参照時は初回初期化時の値を取得
挙動 2/7 … 初期化後は既存の値を取得
class File {
lazy var content: Content = Content(path: self.path)
}
let file = File()
let content1 = file.content // いったん初期化が行われると
file.path = newPath // 関係するものを更新しても
let content2 = file.content // 得られる値は連動しない
Lazy Variables
▶ 値は自由に代入できる
▶ 初期化コードとは無関係に設定可能
挙動 3/7 … 自由に代入可能
class File {
lazy var content: Content = Content(path: somePath)
}
// ここでは content は初期化されない
let file = File()
// 自分で値を自由に設定できる
file.content = Content(path: anotherPath)
Lazy Variables
▶ 参照しなければ初期化されない
▶ 使わなければ初期化処理を省略できる
挙動 4/7 … 初期化の省略
class File {
lazy var content: Content = Content(path: somePath)
}
// ここでは content は初期化されない
let file = File()
// その後 content を参照しなければ、初期化は行われない
Lazy Variables
▶ 未初期化のときにだけ初期化される
▶ 参照前の代入も初期化とみなす
挙動 5/7 … 初期化コードを使わない初期化
class File {
lazy var content: Content = Content(path: somePath)
}
let file = File()
// 参照前に content に値を代入すると …
file.content = Content(path: anotherPath)
// 初めての参照時でも初期化コードは実行されない
let content = file.content
Lazy Variables
▶ 初期化コードは参照直前に実行
▶ 意識的に初期化完了を待つ必要なし
挙動 6/7 … 初期化は同期的に実施
class File {
lazy var content: Content
= Content(path: somePath)
}
let file = File()
// 初めての content 参照
let content = file.content
// 初期化して
self.content
= Content(path: somePath)
// 取得する
return self.content
Lazy Variables
▶ プロトコルが求めるプロパティに対して使える
▶ インスタンス生成後まで初期化を延期できる
挙動 7/7 … プロトコルに対する実装で使用可能
protocol MyProtocol {
// 非オプショナルな型を求められても
var property: Int { get }
}
class MyObject : MyProtocol {
// 初期化をインスタンス生成後まで遅延可能
lazy var property: Int = self.updateProperty()
}
特徴と利用場面
参照直前まで
既定値の代入を遅延できるプロパティ
Lazy Variables
特徴
Lazy Variables
利用場面
▶ 計算に時間のかかるプロパティで
▶ 必ず使うとは限らないが
▶ 使うなら各所で何度も参照する場面
▶ 自身の値で初期化したいプロパティで、
▶ 明確な初期化タイミングを定められず、
▶ 自身の値が変化しても影響を受けず、
▶ 別の値に書き換える道も提供したい場面
注意
Lazy Variables
▶ ゲッターも mutating 扱い
▶ 構造体だと var に格納しないと参照できない
注意 1/4
struct File {
lazy var content: Content = Content(path: somePath)
}
let file = File()
let content = file.content
cannot use mutating getter on immutable
value: 'file' is a 'let' constant
Lazy Variables
▶ 初期化以降の状態変化は連動しない
▶ 初期化後の状態と矛盾する可能性
注意 2/4
class File {
lazy var content: Content = Content(path: self.path)
}
let file = File()
let content1 = file.content // 現在のパスから初期化されたら
file.path = newPath // その後にパスが変更されても
let content2 = file.content // 古いパスのコンテンツが得られる
Lazy Variables
▶ 遅延初期化を除き、普通のプロパティと同等
▶ 初期化式と無関係な独自の値を自由に設定可能
注意 3/4
class File {
lazy var content: Content = Content(path: somePath)
}
let file = File()
// 初期化式とは無関係な値をいつでも設定できる
file.content = Content(text: "TEXT 1")
// 何度でも設定できる
file.content = Content(text: "TEXT 2")
Lazy Variables
▶ 予測困難な初期化タイミング
▶ マルチスレッドで扱うときに悲劇を生むかも
注意 4/4
class File {
lazy var content: Content = Content(path: somePath)
}
// どちらで content が初期化される?
func pushButton(sender: AnyObject) {
contentView.content = file.content
}
func updateNotification(notification: NSNotification) {
contentView.content = file.content
}
HIPSTER SWIFT
オート
クロージャー
強く参照 !
強く参照 !
循環
しない !
strong reference
class MyClass {
lazy var calculate1: () -> Int = self.calculate3
lazy var calculate2: () -> Int = { () -> Int in
return self.calculate3()
}
func calculate3() -> Int { return 10 }
}
let obj = MyClass()
obj.calculate1() // 循環参照する
obj.calculate2() // 循環参照する
obj.calculate3() // 循環参照しない
HIPSTER SWIFT
循環参照を起こす例
関連する話題
lazy var から広がる話
大域変数
大域変数も lazy
大域変数
▶ 初めて使うタイミングで初期化される
▶ 内部的に lazy var として扱われる
遅延初期化
var bundle = NSBundle.mainBundle()
class File {
init() {
self.content
= Content(path: bundle.bundlePath)
}
}
ここで初めて
初期化される
大域変数
▶ 大域変数は let で宣言できる
▶ 既定値にしかならないことを保証可能
既定値を保証
let bundle = NSBundle.mainBundle()
class File {
init() {
bundle = NSBundle(forClass: Object.self)
}
} Cannot assign to value: 'bundle' is a 'let' constant
大域変数
▶ 大域変数はモジュールの名前空間に所属
▶ 他のモジュールと衝突しない
名前空間の活用
public let defaultManager = ...
func method() {
let manager = MyModule.defaultManager
}
MyModule で定義
アプリで使用
lazy var と似ている機能
ImplicitlyUnwrappedOptional
( Type! )
ImplicitlyUnwrappedOptional
▶ 値が無いことを表現できる型
▶ 値がある前提で扱える
概要
// 値が無いまま存在させて、
var content: Content! = nil
// 値を後から設定できる
content = Content(path: path)
// 普通の変数のように操作する
doSomethingWithData(content.data)
値がなければ
強制終了
使う時には
値が入っていることを約束する
プログラマーが!
ImplicitlyUnwrappedOptional
意図
ImplicitlyUnwrappedOptional
▶ 初期化を遅らせることができる
▶ 初期化されているものとして使用できる
lazy var と似ているところ
▶ 適切なタイミングで初期化が必要
lazy var と決定的に異なるところ
初期化のタイミングを
想定できる!
特徴
初期化タイミングを制御できるなら
ImplicitlyUnwrappedOptional
lazy var
×
ImplicitlyUnwrappedOptional
lazy var × ImplicitlyUnwrappedOptional
▶ 初期化を参照時まで遅らせる
▶ 初期値を決めておける
lazy var
▶ 使うときに値が入っていることを約束する
▶ 値がないことを表現できる
ImplicitlyUnwrappedOptional
性質
ゾンビっぽい変数が生まれる
😱
※ ただしプロパティでの使用に限る
class File {
lazy var content: Content! = Content(path: self.path)
}
let file = File()
// content を参照すると初期化される
let content = file.content
// ImplicitlyUnwrappedOptional なので nil を入れられる
file.content = nil
// nil のときに再び content を参照すると再初期化される
let content = file.content
lazy var × ImplicitlyUnwrappedOptional
値を消しても復活する変数
画像キャッシュの機能などに
応用できるかもしれない
lazy
超かっこいい … 😆
lazy var
▶ 初期化されるタイミングが読めない
▶ 読み書きともに mutating 扱い
▶ 複数スレッドで衝突する可能性
▶ 初期化式とは無関係に値を入れられる
注意したいところ
▶ 単に “便利だから” という理由で使わない
▶ 初期化を遅らせたいだけなら

ImplicitlyUnwrappedOptional も検討したい
魔力にご用心
lazy の
まとめ
lazy var の特徴を知る
1. HIPSTER SWIFT
2. Lazy Variables の動き
3. 大域変数も lazy 扱い
4. ImplicitlyUnwrappedOptional は

動きが lazy var と似ている
5. lazy var × ImplicitlyUnwrappedOptional で

何度だって蘇る変数が生まれる
6. lazy の魔力にご用心

lazy var の特徴を知る #cocoa_kansai #cswift