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

62
EZ-NET 熊⾕友宏 http://ez-net.jp/ 2016.03.12 第66回 Cocoa 勉強会勉強会 lazy var の特徴を知る Swift カジュアルプログラミング Swift 2.1.1 2016.04.02 第6回 カジュアル Swift 勉強会

Upload: tomohiro-kumagai

Post on 14-Apr-2017

2.198 views

Category:

Engineering


3 download

TRANSCRIPT

Page 1: lazy var の特徴を知る #cocoa_kansai #cswift

EZ-NET 熊⾕友宏 http://ez-net.jp/

2016.03.12 第66回 Cocoa 勉強会勉強会

lazy var の特徴を知るSwift カジュアルプログラミング

Swift 2.1.1

2016.04.02 第6回 カジュアル Swift 勉強会

Page 2: lazy var の特徴を知る #cocoa_kansai #cswift

熊谷友宏

Xcode 5 徹底解説 MOSA

Xcode 5 の全機能を徹底的に解説した本

OSX/iOS 系の歴史深い有料会員制の勉強会

紙版は絶版、電子書籍は販売中

Xcode 7 でも役立つはず 法人会員も多数

@es_kumagai EZ-NET http://ez-net.jp/

書籍 / 登壇

Page 3: lazy var の特徴を知る #cocoa_kansai #cswift

熊谷友宏

横浜 iPhone 開発者勉強会#yidev

わいわい・ゆるく、iPhone 開発者のみんなで楽しく過ごすのが目的の会

【 横浜・馬車道 】カジュアル Swift 勉強会

#cswift

ゆるくみんなで Swift を語らえる場を作りたくて始めた会

【 横浜・青葉台 】

第6回を 2016-04-02 に開催予定

@es_kumagai EZ-NET http://ez-net.jp/

勉強会

Page 4: lazy var の特徴を知る #cocoa_kansai #cswift

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

CodePiece

iOS, OS X, Apple Watch アプリ

ソースコードを Twitter と Gist に同時投稿できる。

いつもの電卓

計算式も見える電卓アプリ。 watchOS 1 対応

音で再配達ゴッド

簡単操作で 再配達の申し込み。

EZ-NET IP Phone

iPhone でひかり電話を使う。 自宅 LAN からの利用専用

Page 5: lazy var の特徴を知る #cocoa_kansai #cswift

CodePiece for OS X勉強会を楽しむアプリ

ソースコードを Twitter と Gist に同時投稿できる 勉強会で知見をみんなと共有したい時とかに便利!

できること

#cswift

Page 6: lazy var の特徴を知る #cocoa_kansai #cswift

try! Swift2016.03.02 - 2016.03.04

Page 7: lazy var の特徴を知る #cocoa_kansai #cswift

try! Swift2016 初日

Page 8: lazy var の特徴を知る #cocoa_kansai #cswift

try! Swift2016 二日目

Page 9: lazy var の特徴を知る #cocoa_kansai #cswift

try! Swift2016 最終日

Page 10: lazy var の特徴を知る #cocoa_kansai #cswift

try! SwiftThe most impressive speaker for me ! 😆

HIPSTER SWIFT

★ @noescape ★ @autoclosure ★ inline lazy vars ★ variadic parameters ★ labeled loops ★ type omitting

Page 11: lazy var の特徴を知る #cocoa_kansai #cswift

HIPSTER SWIFTinline lazy vars

Page 12: lazy var の特徴を知る #cocoa_kansai #cswift

Lazy Variables初期化を参照時まで遅延できる変数

Page 13: lazy var の特徴を知る #cocoa_kansai #cswift

HIPSTER SWIFT

▶ 値型プロパティを lazy 付きで定義 ▶ 右辺で参照時に設定する値を記載

Lazy Variables

class MyClass {

lazy var value: Int = { return self.calculate() }()

}

Page 14: lazy var の特徴を知る #cocoa_kansai #cswift

HIPSTER SWIFT評価式の書式

lazy var value: Int = { return self.calculate() }()

これが …

lazy var value: Int = self.calculate()

こう書ける

Page 15: lazy var の特徴を知る #cocoa_kansai #cswift

HOW BEAUTIFUL ...

BUT … SAFE ?

Page 16: lazy var の特徴を知る #cocoa_kansai #cswift

class MyClass {

lazy var value: Int = self.calculate()

}

HIPSTER SWIFT評価式の書式

var obj: MyClass? = MyClass()

obj.value

obj = nil

循環参照しない

初期化コードで self を使っていても …

DEINIT!

Page 17: lazy var の特徴を知る #cocoa_kansai #cswift

AWESOME !! 🎉

Page 18: lazy var の特徴を知る #cocoa_kansai #cswift

class MyClass {

lazy var value: Int = self.calculate()

}

HIPSTER SWIFT気になったところ

Super Lazy Vars

オート クロージャー

強く参照 !

強く参照 !

どういうことだろう…

循環 しない !

Page 19: lazy var の特徴を知る #cocoa_kansai #cswift

Lazy Variablesもっと理解して使いたい

Page 20: lazy var の特徴を知る #cocoa_kansai #cswift

Lazy Variables

▶ 初期値の設定を参照直前まで延期できる ▶ 主に保存型プロパティで使用

概要

// 定義の仕方

class File { lazy var content: Content = Content(path: somePath) }

Page 21: lazy var の特徴を知る #cocoa_kansai #cswift

File

Lazy Variables初期化タイミング

= Content(path: somePath)

Contents

lazy var

参照

instance

Contents

Page 22: lazy var の特徴を知る #cocoa_kansai #cswift

File

Lazy Variables自身の機能で初期化できる

= Content(path: self.path)

Contents

lazy var

参照

instance

Contents

参照のときは インスタンス生成済みなので 初期化処理で self も使える

Page 23: lazy var の特徴を知る #cocoa_kansai #cswift

プロパティを自分自身の機能で初期化したいときに便利 … なもの?

そう単純なものでもなさそう

Lazy Variables使いどころ?

Page 24: lazy var の特徴を知る #cocoa_kansai #cswift

挙動

Page 25: lazy var の特徴を知る #cocoa_kansai #cswift

Lazy Variables

▶ 参照のときに初期化が行われる ▶ 初期化して保存してすぐ参照する

挙動 1/7 … 初期化のタイミング

class File { lazy var content: Content = Content(path: somePath) }

// ここでは content は初期化されない let file = File()

// ここで初めて content が初期化され、値がプロパティに保持される let content = file.content

Page 26: lazy var の特徴を知る #cocoa_kansai #cswift

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 // 得られる値は連動しない

Page 27: lazy var の特徴を知る #cocoa_kansai #cswift

Lazy Variables

▶ 値は自由に代入できる ▶ 初期化コードとは無関係に設定可能

挙動 3/7 … 自由に代入可能

class File { lazy var content: Content = Content(path: somePath) }

// ここでは content は初期化されない let file = File()

// 自分で値を自由に設定できる file.content = Content(path: anotherPath)

Page 28: lazy var の特徴を知る #cocoa_kansai #cswift

Lazy Variables

▶ 参照しなければ初期化されない ▶ 使わなければ初期化処理を省略できる

挙動 4/7 … 初期化の省略

class File { lazy var content: Content = Content(path: somePath) }

// ここでは content は初期化されない let file = File()

// その後 content を参照しなければ、初期化は行われない

Page 29: lazy var の特徴を知る #cocoa_kansai #cswift

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

Page 30: lazy var の特徴を知る #cocoa_kansai #cswift

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

Page 31: lazy var の特徴を知る #cocoa_kansai #cswift

Lazy Variables

▶ プロトコルが求めるプロパティに対して使える ▶ インスタンス生成後まで初期化を延期できる

挙動 7/7 … プロトコルに対する実装で使用可能

protocol MyProtocol { // 非オプショナルな型を求められても var property: Int { get } }

class MyObject : MyProtocol { // 初期化をインスタンス生成後まで遅延可能 lazy var property: Int = self.updateProperty()

}

Page 32: lazy var の特徴を知る #cocoa_kansai #cswift

特徴と利用場面

Page 33: lazy var の特徴を知る #cocoa_kansai #cswift

参照直前まで既定値の代入を遅延できるプロパティ

Lazy Variables特徴

Page 34: lazy var の特徴を知る #cocoa_kansai #cswift

Lazy Variables利用場面

▶ 計算に時間のかかるプロパティで ▶ 必ず使うとは限らないが ▶ 使うなら各所で何度も参照する場面

▶ 自身の値で初期化したいプロパティで、 ▶ 明確な初期化タイミングを定められず、 ▶ 自身の値が変化しても影響を受けず、 ▶ 別の値に書き換える道も提供したい場面

Page 35: lazy var の特徴を知る #cocoa_kansai #cswift

注意

Page 36: lazy var の特徴を知る #cocoa_kansai #cswift

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

Page 37: lazy var の特徴を知る #cocoa_kansai #cswift

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 // 古いパスのコンテンツが得られる

Page 38: lazy var の特徴を知る #cocoa_kansai #cswift

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")

Page 39: lazy var の特徴を知る #cocoa_kansai #cswift

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 }

Page 40: lazy var の特徴を知る #cocoa_kansai #cswift

HIPSTER SWIFT

オート クロージャー

強く参照 !

強く参照 !

循環 しない !

strong reference

Page 41: lazy var の特徴を知る #cocoa_kansai #cswift

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循環参照を起こす例

Page 42: lazy var の特徴を知る #cocoa_kansai #cswift

関連する話題lazy var から広がる話

Page 43: lazy var の特徴を知る #cocoa_kansai #cswift

大域変数

Page 44: lazy var の特徴を知る #cocoa_kansai #cswift

大域変数も lazy

Page 45: lazy var の特徴を知る #cocoa_kansai #cswift

大域変数

▶ 初めて使うタイミングで初期化される ▶ 内部的に lazy var として扱われる

遅延初期化

var bundle = NSBundle.mainBundle()

class File {

init() { self.content = Content(path: bundle.bundlePath) } }

ここで初めて 初期化される

Page 46: lazy var の特徴を知る #cocoa_kansai #cswift

大域変数

▶ 大域変数は let で宣言できる ▶ 既定値にしかならないことを保証可能

既定値を保証

let bundle = NSBundle.mainBundle()

class File {

init() { bundle = NSBundle(forClass: Object.self) } }

Cannot assign to value: 'bundle' is a 'let' constant

Page 47: lazy var の特徴を知る #cocoa_kansai #cswift

大域変数

▶ 大域変数はモジュールの名前空間に所属 ▶ 他のモジュールと衝突しない

名前空間の活用

public let defaultManager = ...

func method() {

let manager = MyModule.defaultManager }

MyModule で定義

アプリで使用

Page 48: lazy var の特徴を知る #cocoa_kansai #cswift

lazy var と似ている機能

Page 49: lazy var の特徴を知る #cocoa_kansai #cswift

ImplicitlyUnwrappedOptional( Type! )

Page 50: lazy var の特徴を知る #cocoa_kansai #cswift

ImplicitlyUnwrappedOptional

▶ 値が無いことを表現できる型 ▶ 値がある前提で扱える

概要

// 値が無いまま存在させて、 var content: Content! = nil

// 値を後から設定できる content = Content(path: path)

// 普通の変数のように操作する doSomethingWithData(content.data)

値がなければ 強制終了

Page 51: lazy var の特徴を知る #cocoa_kansai #cswift

使う時には

値が入っていることを約束する

プログラマーが!

ImplicitlyUnwrappedOptional意図

Page 52: lazy var の特徴を知る #cocoa_kansai #cswift

ImplicitlyUnwrappedOptional

▶ 初期化を遅らせることができる ▶ 初期化されているものとして使用できる

lazy var と似ているところ

▶ 適切なタイミングで初期化が必要

lazy var と決定的に異なるところ

初期化のタイミングを 想定できる!

特徴

Page 53: lazy var の特徴を知る #cocoa_kansai #cswift

初期化タイミングを制御できるなら

ImplicitlyUnwrappedOptional

Page 54: lazy var の特徴を知る #cocoa_kansai #cswift

lazy var ×

ImplicitlyUnwrappedOptional

Page 55: lazy var の特徴を知る #cocoa_kansai #cswift

lazy var × ImplicitlyUnwrappedOptional

▶ 初期化を参照時まで遅らせる ▶ 初期値を決めておける

lazy var

▶ 使うときに値が入っていることを約束する ▶ 値がないことを表現できる

ImplicitlyUnwrappedOptional

性質

Page 56: lazy var の特徴を知る #cocoa_kansai #cswift

ゾンビっぽい変数が生まれる

😱

※ ただしプロパティでの使用に限る

Page 57: lazy var の特徴を知る #cocoa_kansai #cswift

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値を消しても復活する変数

Page 58: lazy var の特徴を知る #cocoa_kansai #cswift

画像キャッシュの機能などに

応用できるかもしれない

Page 59: lazy var の特徴を知る #cocoa_kansai #cswift

lazy

超かっこいい … 😆

Page 60: lazy var の特徴を知る #cocoa_kansai #cswift

lazy var

▶ 初期化されるタイミングが読めない ▶ 読み書きともに mutating 扱い ▶ 複数スレッドで衝突する可能性 ▶ 初期化式とは無関係に値を入れられる

注意したいところ

▶ 単に “便利だから” という理由で使わない ▶ 初期化を遅らせたいだけなら

ImplicitlyUnwrappedOptional も検討したい

Page 61: lazy var の特徴を知る #cocoa_kansai #cswift

魔力にご用心lazy の

Page 62: lazy var の特徴を知る #cocoa_kansai #cswift

まとめlazy var の特徴を知る

1. HIPSTER SWIFT

2. Lazy Variables の動き

3. 大域変数も lazy 扱い

4. ImplicitlyUnwrappedOptional は動きが lazy var と似ている

5. lazy var × ImplicitlyUnwrappedOptional で何度だって蘇る変数が生まれる

6. lazy の魔力にご用心