Swift static(静的)変数とは?

〽️ SwiftUI準備編。







SwiftUI、いきなりつまづく。

こんにちは、「ふ」です。
Xcode11で新しいフレームワーク、「Swift UI」が使えるようになりました。公式のチュートリアルで新しいプロジェクトを立ち上げたところ、こういったコードが既に記述されています。

〜 略 〜 struct ContentView_Previews: PreviewProvider { 「「1static var」」 previews: some View { ContentView() } }

「static」て何?

普通の「var」ならわかるけど、「static var」???

〜これがSwiftを学ぶ上でのしんどいところ。簡単なコードでUIを構築する際にも、フレームワークありきで進めなければならない。そのフレームワーク自体は様々な文法を駆使して記述されているので、初学者にとってはいきなりでかい壁が襲いかかります。

今回はSwiftUIを学んでゆく準備編として、「static」とはなんぞや?というところに迫りたいと思います。



取り敢えず書いてみる。

ひとまずコードを書いてみましょう。

class noodle { var taste = "醤油" 「「1static」」 var topping = "焼豚" }

noodleクラスを作って、普通の変数「taste」とstatic変数「topping」を置きました。
「クラス」はあくまで設計図なので実体を持たず、この状態でクラス内の変数を呼び出すことはできません。

print(noodle.taste) 「「4▶︎ error」」

これは一般的ではないとされる方法ですが、クラスの後に「( )」を付ければ一応呼び出せます。ただし値を変更することはできません。

print(noodle「「1()」」.taste) 「「1▶︎ 醤油」」

ところがstaticで宣言した変数は呼び出したり変更することができてしまいます。

print(noodle.topping) 「「1▶︎ 焼豚」」

これは、

インスタンスを作らなくてもアクセスできる

ということになりますね。
もしかしてとても便利?

逆に、インスタンス「miso」を作ってそれぞれの変数を呼び出してみます。

「「3インスタンスを生成」」 var miso = noodle() 「「3普通の変数を呼び出す」」 print(miso.taste) 「「1▶︎ 醤油」」 「「3static変数を呼び出す」」 print(miso.topping) 「「4▶︎ error」」

「miso」クラスからstatic変数を呼び出すことができません。
インスタンス単位でアクセスできない、とは

再度初期化することができない

ことを意味します。



静的/動的。

static var は「静的変数」と呼ばれるもので、全てのプログラムが終了するまで一貫してその値を保持し続ける変数です。対して「動的変数」は関数内で何度でも初期化することができ、関数が終了するとその存在もメモリ上から消滅してしまいます。
「動的変数」の例をみてみましょう。

func dinamic() { 「「3//動的変数を宣言・初期化」」 var menma_count = 0 menma_count += 1 print("メンマは\(menma_count)本入っています。") }

関数内で動的変数「menma_count」を宣言・初期化し、実行のたびに1本増やしてその本数を出力させます。
何度か実行させてみましょう。

dinamic() 「「1▶︎ メンマは1本入っています。」」 dinamic() 「「1▶︎ メンマは1本入っています。」」 dinamic() 「「1▶︎ メンマは1本入っています。」」

関数を実行するたびに「menma_count」は内部で初期化されてしまうので、メンマは一向に増えていきません。悲しい・・・

ではstatic変数とdinamic(動的)変数の両方をクラス内に作って、その挙動を比べてみましょう。

class noodle { 「「3var taste = "醤油" static var topping = "焼豚"」」 「「3//本日のオーダー数」」 「「1static var order」」 = 0 「「3//お客が替え玉した時の皿の数」」 「「4var sara」」 = 0 「「3//売上をカウントしていく」」 func uriage() { 「「1noodle.order」」 += 1 print("本日\(noodle.order)杯目の注文が入りました。") } 「「3//お客ごとの替え玉数をカウント」」 func kaedama() { 「「4sara」」 += 1 print("替え玉を\(sara)回したので皿は\(sara)枚です。") } }

本日のオーダー数「order」をstaticで、お客ごとの替え玉の数「sara」を動的変数にしています。
オーダーが入るたびに関数「uriage()」で合計をカウントし、替え玉を頼まれたら「kaedama()」でお客ごとの皿数を管理します。

お客を1人作ってみましょう。

var kyaku_1 = noodle()

この人はラーメン1杯注文し、替え玉を1回しました。関数を実行させます。

kyaku_1.uriage() 「「1▶︎ 本日1杯目の注文が入りました。」」 kyaku_1.kaedama() 「「1▶︎ 替え玉を1回したので皿は1枚です。」」

これは予想のつく結果ですね。では2人目のお客。この人も替え玉を1回しました。

var kyaku_2 = noodle() kyaku_2.uriage() 「「1▶︎ 本日2杯目の注文が入りました。」」 kyaku_2.kaedama() 「「1▶︎ 替え玉を1回したので皿は1枚です。」」

インスタンスであるお客が何人入店しても、オーダー数「order」はstaticにしてあるため、初期化されずに前回の値を引き継いだまま増えていきます。
一方替え玉の数はお客ごとに会計しなければならないため、動的変数「sara」で扱います。1人入店するごとにその値は「0」に初期化されたところからカウントされます。


static変数の、

値を保持し続ける。

というのはlet(定数)のように「変わらない」という意味ではなく、「初期化は1度しか行われず、変わったら変わりっぱなし」ということですね。



普通のglobal変数とどう違うのか?

扨(さて)、staticについて判明したことを取りあえずまとめます。

staticの特徴

・インスタンスをいちいち生成しなくても呼び出すことができるので、無駄なメモリ消費もなくて便利。

・初期化は1度しか行われず、プログラム内で一貫して値を保持し続けるので、複数のインスタンス間でその値を共有できる。

この辺の事はわかりました。しかしよくよく考えてみると、

じゃあ普通のグローバル変数でええやん。

と思いませんか?

static変数を使うメリット。現在のところはっきりとした事は解明できていません。
ただ実際にアプリを作るにあたっては膨大なコード量となるため、「どこからでもアクセスできる変数」を全てglobalで記述するとその量からして整理がつき辛くなってしまうでしょう。クラスごとに静的変数を呼び出すことによって、分類ができ利便性が向上するのかな?と思います。
globalとstatic、どこがどう違うのか。「ふ」は引き続き調査していく方向です。


今回は挙動を確認するところで終わってしまいましたが、ひとまずはコード内に「static」の文字が出てきてもビビらなくなったでしょうか?だとしたら幸いです。













「ふ」です。

swift、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。

🐧 twitter 🐧