Takahiro Octopress Blog

-1から始める情弱プログラミング

Swiftのグローバルプロパティとスタティックプロパティは自動でlazyになる

はじめに

今日はSwiftでグローバルプロパティを定義した時の挙動についてのメモです。

Swiftではプロパティを定義する時に、わざと遅延評価させるための lazy という修飾子があります。
lazy をつけることで、そのプロパティが利用される時に、初期化されメモリが消費されるため、メモリの効率性を上げることに一役買います。

実際の定義は下記の通りです。

1
2
3
4
5
6
// ViewController.swift

class ViewController: UIViewController {
    lazy var localProp = "local"
    ...
}

これがSwiftで グローバルプロパティスタティックプロパティ を定義した時に自動的に付与されます。

実験

では、実際に実験してみましょう。

事前準備

まずは下記のような Sample クラスを定義します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 実験用のクラス

class Sample {
  let label: String

  init(label: String) {
      self.label = label
      print("initされたよ! - \(label)")
  }

  deinit {
      print("deinitされたよ! - \(label)")
  }
}

そして、下記のような Storyboard を用意します。

Storyboard

各種機能を箇条書きで述べると下記の通りです。

  • 中央の『Next Page』ボタンを持つVCが FirstViewController
  • 右端のVCが SecondViewController
  • FirstViewController の『Next Page』ボタンをタップすると SecondViewController に遷移する
  • SecondViewController に各種プロパティを定義
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// SecondViewController.swift
import Foundation
import UIKit

/// グローバルプロパティ
var global_prop = Sample(label: "global_prop")

class SecondViewController: UIViewController {

    /// 通常のローカルプロパティ
    var local_prop = Sample(label: "local_prop")
    /// 遅延実行されるローカルプロパティ
    lazy var local_lazy_prop = Sample(label: "local_lazy_prop")
    /// スタティックプロパティ
    static var static_prop = Sample(label: "static_prop")

    override func viewDidLoad() {
        super.viewDidLoad()

        // 各種プロパティにアクセスする
        print(global_prop)
        print(local_prop)
        print(local_lazy_prop)
        print(SecondViewController.static_prop)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    deinit {
        print("SecondViewControllerがdeinitされました")
    }
}

実験結果

準備が整ったので、実際に挙動を見ていきましょう。

まずは、 FirstViewController の『Next Page』をタップして SecondViewController に遷移した場合です。

結果は、

1
2
3
4
initされたよ! - local_prop
initされたよ! - global_prop
initされたよ! - local_lazy_prop
initされたよ! - static_prop

の順番でログが出力されました。

このことから、

  • local_propSecondViewController 初期化時に初期化される
  • global_prop はアクセス時に初期化される
  • local_lazy_prop はアクセス時に初期化される
  • static_prop はアクセス時に初期化される

ことがわかります。

続いて、 SecondViewController のナビゲーションバーの『Back』をタップして前の画面に戻ってみます。

1
2
3
SecondViewControllerdeinitされました
deinitされたよ! - local_prop
deinitされたよ! - local_lazy_prop

のようにログが出力されました。

このことから、

  • local_propSecondViewControllerdeinit されるタイミングで deinit される
  • local_lazy_propSecondViewControllerdeinit されるタイミングで deinit される
  • global_propSecondViewControllerdeinit されても deinit されない
  • static_propSecondViewControllerdeinit されても deinit されない

ことがわかります。

さらに、再度 FirstViewController の『Next Page』をタップして SecondViewController に画面遷移してみます。

すると、

1
2
initされたよ! - local_prop
initされたよ! - local_lazy_prop

のようにログが出力されました。

このことから、

  • local_propSecondViewController 初期化時に初期化される
  • local_lazy_prop はアクセス時に初期化される
  • global_propstatic_prop は既に初期化済みなので、初期化されない

ことがわかります。

グローバルプロパティ vs スタティックプロパティ

因みに、グローバルプロパティとスタティックプロパティの挙動は下記の点で似ています。

  • 特定のクラスを初期化しなくても利用できる
  • 特定のクラスが deinit されてもプロパティ自体は deinit されない

そうなると、グローバルプロパティとスタティックプロパティそれぞれ使い分けに疑問を抱くかもしれません。
しかしながら、この2つは全く利用用途が異なります。

  • グローバルプロパティ
    • グローバルにアクセスする必要がある場合に利用する
    • 特定のクラスに依存するような関係性を持たない
    • 名前空間はグローバル(全体)に影響があるため、十分注意が必要
  • スタティックプロパティ
    • 特定のクラスを初期化せずともアクセスする必要がある場合に利用する
    • 特定のクラスに依存する関係性ではある
      • 特定のクラスを初期化せずとも利用できるが、特定のクラスが持つ役割に含まれる
    • 名前空間は特定のクラス内に留まる

上記から、より適切な使い分けをするように気をつけましょう。

まとめ

ではまとめます。

  • グローバルプロパティは自動で lazy 付与と同じ扱いになる
  • スタティックプロパティは自動で lazy 付与と同じ扱いになる
  • グローバルプロパティとスタティックプロパティは特定のクラスが deinit されても deinit されない
  • グローバルプロパティはグローバルにアクセスが必要な場合に利用する
  • スタティックプロパティは特定のクラス内に定義して利用することで、その役割を明確にして利用する

ということで本日はここまで。

Comments