More Related Content Similar to lazy var の特徴を知る #cocoa_kansai #cswift (20) More from Tomohiro Kumagai (20) lazy var の特徴を知る #cocoa_kansai #cswift2. 熊谷友宏
Xcode 5 徹底解説 MOSA
Xcode 5 の全機能を
徹底的に解説した本
OSX/iOS 系の歴史深い
有料会員制の勉強会
紙版は絶版、電子書籍は販売中
Xcode 7 でも役立つはず 法人会員も多数
@es_kumagai
EZ-NET http://ez-net.jp/
書籍 / 登壇
5. CodePiece for OS X
勉強会を楽しむアプリ
ソースコードを Twitter と Gist に同時投稿できる
勉強会で知見をみんなと共有したい時とかに便利!
できること
#cswift
10. try! Swift
The most impressive speaker for me ! 😆
HIPSTER SWIFT
★ @noescape
★ @autoclosure
★ inline lazy vars
★ variadic parameters
★ labeled loops
★ type omitting
13. HIPSTER SWIFT
▶ 値型プロパティを lazy 付きで定義
▶ 右辺で参照時に設定する値を記載
Lazy Variables
class MyClass {
lazy var value: Int = {
return self.calculate()
}()
}
16. class MyClass {
lazy var value: Int = self.calculate()
}
HIPSTER SWIFT
評価式の書式
var obj: MyClass? = MyClass()
obj.value
obj = nil
循環参照しない
初期化コードで self を使っていても …
DEINIT!
18. class MyClass {
lazy var value: Int = self.calculate()
}
HIPSTER SWIFT
気になったところ
Super Lazy Vars
オート
クロージャー
強く参照 !
強く参照 !
どういうことだろう…
循環
しない !
25. Lazy Variables
▶ 参照のときに初期化が行われる
▶ 初期化して保存してすぐ参照する
挙動 1/7 … 初期化のタイミング
class File {
lazy var content: Content = Content(path: somePath)
}
// ここでは content は初期化されない
let file = File()
// ここで初めて content が初期化され、値がプロパティに保持される
let content = file.content
26. 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 // 得られる値は連動しない
27. Lazy Variables
▶ 値は自由に代入できる
▶ 初期化コードとは無関係に設定可能
挙動 3/7 … 自由に代入可能
class File {
lazy var content: Content = Content(path: somePath)
}
// ここでは content は初期化されない
let file = File()
// 自分で値を自由に設定できる
file.content = Content(path: anotherPath)
28. Lazy Variables
▶ 参照しなければ初期化されない
▶ 使わなければ初期化処理を省略できる
挙動 4/7 … 初期化の省略
class File {
lazy var content: Content = Content(path: somePath)
}
// ここでは content は初期化されない
let file = File()
// その後 content を参照しなければ、初期化は行われない
29. 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
30. 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
31. Lazy Variables
▶ プロトコルが求めるプロパティに対して使える
▶ インスタンス生成後まで初期化を延期できる
挙動 7/7 … プロトコルに対する実装で使用可能
protocol MyProtocol {
// 非オプショナルな型を求められても
var property: Int { get }
}
class MyObject : MyProtocol {
// 初期化をインスタンス生成後まで遅延可能
lazy var property: Int = self.updateProperty()
}
36. 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
37. 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 // 古いパスのコンテンツが得られる
38. 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")
39. 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
}
41. 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
循環参照を起こす例
45. 大域変数
▶ 初めて使うタイミングで初期化される
▶ 内部的に lazy var として扱われる
遅延初期化
var bundle = NSBundle.mainBundle()
class File {
init() {
self.content
= Content(path: bundle.bundlePath)
}
}
ここで初めて
初期化される
46. 大域変数
▶ 大域変数は let で宣言できる
▶ 既定値にしかならないことを保証可能
既定値を保証
let bundle = NSBundle.mainBundle()
class File {
init() {
bundle = NSBundle(forClass: Object.self)
}
} Cannot assign to value: 'bundle' is a 'let' constant
55. lazy var × ImplicitlyUnwrappedOptional
▶ 初期化を参照時まで遅らせる
▶ 初期値を決めておける
lazy var
▶ 使うときに値が入っていることを約束する
▶ 値がないことを表現できる
ImplicitlyUnwrappedOptional
性質
57. 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
値を消しても復活する変数
60. lazy var
▶ 初期化されるタイミングが読めない
▶ 読み書きともに mutating 扱い
▶ 複数スレッドで衝突する可能性
▶ 初期化式とは無関係に値を入れられる
注意したいところ
▶ 単に “便利だから” という理由で使わない
▶ 初期化を遅らせたいだけなら
ImplicitlyUnwrappedOptional も検討したい
62. まとめ
lazy var の特徴を知る
1. HIPSTER SWIFT
2. Lazy Variables の動き
3. 大域変数も lazy 扱い
4. ImplicitlyUnwrappedOptional は
動きが lazy var と似ている
5. lazy var × ImplicitlyUnwrappedOptional で
何度だって蘇る変数が生まれる
6. lazy の魔力にご用心