Swiftのlazyの使い所

f:id:otowa_jp:20160225091630p:plain


このコーナーは、iOSアプリ開発でなあなあにしてた部分について調べて文章にすることで理解を深めようというものです。
今回は、Swiftのlazyの使い所について。

そもそもlazyって何?


遅延初期化(lazy initialization)をサポートするのがSwiftにおけるlazyであり、
lazyで初期化されたプロパティを遅延格納型プロパティ(lazy Stored property)と呼びます。
遅延格納型プロパティの動きを簡単にいうと、飲み会に「行けたら行く」って言ってるAさんの分のビール何本必要かな、いやAさんが来たら買えばいいでしょ。みたいな感じ。

  1. 必要とされたときに値を初めて決定する
  2. クラスと構造体で使用可能
  3. 定数ではなく変数として定義する
  4. プロパティオブザーバが使用できない

これさえ押さえておけばlazyを適切に使えそう。

lazyの使い所


今回の結論にあたります。主な使い所はこの2点。

  1. オブジェクトの初期化に合わせてプロパティの初期値を決定したいとき
  2. コストの高い処理を含んだオブジェクトの初期化を制限したいとき
オブジェクトの初期化に合わせてプロパティの初期値を決定したいとき
import Foundation

class Product {

    var name: String
    var category: String

    // 遅延格納型プロパティの定義 
    lazy var secondhandName: String = {
        [unowned self] in

        return "中古の\(self.name)"

    }()

    lazy var latestName: String = self.getLatestName()

    init(name: String, category: String) {

        self.name = name
        self.category = category

    }

    func getLatestName() -> String {

        return "最新の\(self.name)!"

    }
}

let product: Product = Product(name: "フライパン", category: "調理器具")
print("product.name", product.name) // フライパン 
print("product.secondhandName", product.secondhandName) // 中古のフライパン
print("product.latestName", product.latestName) // 最新のフライパン
コストの高い処理を含んだオブジェクトの初期化を制限したいとき
import Foundation

class Person {
    
    var name: String
    // 遅延格納型プロパティの定義 
    lazy var calculator = Calculator()
    
    init(name: String) {
        self.name = name
        print("Personオブジェクトが初期化されたよ")
    }
    
    func calculateFate() {
        self.calculator.doSomething()
    }
    
}

// コストの高いクラス
class Calculator {
    
    init() {
        print("Calculatorオブジェクトが初期化されたよ")
    }
    
    func doSomething() {
        // 省略
    }
}

let person: Person = Person(name: "Otowa") // Personオブジェクトが初期化されたよ
person.calculateFate() // Calculatorオブジェクトが初期化されたよ(Calculatorのオブジェクトが必要になったタイミングで初期化される)


こういうのがさくっと書けるのSwiftの素敵なとこだと思います。