LoginSignup
6
6

More than 3 years have passed since last update.

【Swift】プロパティ総まとめ~公式ドキュメントをもとに全部まとめてみた~

Last updated at Posted at 2020-05-17

プロパティ

そもそもプロパティとは、なんぞやというところから

classやstruct,enumでよく見るこいつです。

class
class{
  let men: String = "男"
}

このように、プロパティは型(クラス、構造体、列挙型)を構成する要素の一つで、型もしくは型のインスタンスに紐づいた値を指します。
(ちなみに、型を構成する他の要素には、メソッド・イニシャライザ・ネスト・サブスクリプトなどがあります。)

本記事では、プロパティの公式ドキュメントの内容を網羅してまとめていきます!

本記事の構成

  • Stored Properties(ストアド・プロパティ)
    • Lazy Stored Propertiesz(レイジー・ストアドプロパティ)
  • Computed Properties(コンピューテッド・プロパティ)
  • Property Observers(プロパティオブザーバー)
  • Property Wrapper(プロパティラッパー)
  • Type Property

値を保有する ストアド・プロパティ

ストアド(Stored)は、「保有した」という意味です。
値には定数と変数があります。

  • letキーワード:定数を保持
  • varキーワード:変数の保持
StorerdProperties
struct StoredProperity{
  let test: Int 
  var test2: String
}

上記のようなものをよく見るパターンですね。
このストアド・プロパティを細分化するとレイジー・ストアドプロパティなるものがあります。

アクセスされるまで初期化を遅延させる レイジー・ストアドプロパティ

  • 初期値が、外部要因に依存している場合(インスタンスの初期化が完了するまで値がわからない)
  • 初期値に不必要(or 必要になるまで実行しなくて良い)で複雑な計算量が多いセットアップをする場合

などで役に立ちます!
lazy var ~のようにlazy修飾子をつけます。
再代入ができないletキーワードにはもちろん使えません。

lazyStoredProperty
class data{
  var fileName = "data.txt"
}

class getData{
  lazy var importer = data()
  var data = [String]()
}

let lazyStoredProperty = getData() //ここでは、まだimporterは初期化されない
print(lazyStoredProperty.importer)  //ここで初めてimporterにアクセスして初期化が行われる

値の変化を観察・応答する プロパティ・オブザーバ

レイジー以外のストアド・プロパティを対象に追加できます。
プロパティ・オブザーバを追加することで、値の変化前・変化後それぞれのタイミングで処理応答をすることができます。

具体的には、
willSet→値が格納される直前に呼び出されます。新しい値はデフォルトでnewValue
didSet→新しい値が格納された直後に呼び出されます。古い値はデフォルトでoldValue

class test{
  var A:Int = 0 {
      willSet(newValue){
        print("値が\(newValue)に更新されます。")
      }
      didSet {
        print("\(A)が新しい値で、\(oldValue)が古い値です。")
      }
  }
}

値を保有しない計算型 コンピューテッド・プロパティ

コンピューテッド(computed)は、「計算された」という意味です。
ゲッター/セッターを用いて、他のプロパティーの値から間接的に値を取得・設定する。

ゲッター・セッターについて簡単に記述すると、

  • ゲッター
    • 他のプロパティの値を元に処理をし、自身のプロパティの値を取得する(処理が単一の場合returnを省略できる)
  • セッター
    • 自身の新しい値(デフォルトでは、「newValue」)を元に処理をし、他のプロパティの値を更新する

基本的にゲッターは必須だが、セッターは任意です。
セッターがない場合は、読み取り専用コンピューテッド・プロパティと呼ばれます。

class computedProperty {
  var name = "田中さん"
  var circumstance = "田中さんはget待ちだ"
  var GetSet: String {
    get {
      if name == "田中さん"{
        return "田中さんをGetした"
      }
    set {
      if newValue == "田中さんをGetした"{
        circumstance = "「田中さんはGetされた」とsetされた"
    }
}

複数のプロパティの処理を管理する プロパティ・ラッパー

プロパティラッパーは、一言でういとプロパティに関する処理を他の型に移譲するものです。
このプロパティラッパーをつかうことによって、個別の実装ケースに対してハードコーディングする必要がなくなります。

プロパティラッパーの使い方

  • Property Wrapper にしたい型に@propertyWrapperをつける
  • Property Wrapper 型にはwrappedValueというインスタンスプロパティを持つ
  • Property Wrapper を使用したい他の型のプロパティの頭に@propertyWrapperの型名をつける

プロパティラッパーを使った場合

UsingPropertyWrapper
import UIKit

var str = "Hello, playground"

@propertyWrapper
struct TwelveOrLess {
    private var number: Int
    init(){self.number = 0}
    var wrappedValue:Int {  //このwrappedValueが
        get {return number}
        set {number = min(newValue, 12)} // 上限値を12とする
    }
}

struct SmallRectangle {
    @TwelveOrLess var height: Int
    @TwelveOrLess var weight: Int
}

var rectangle = SmallRectangle()
print(rectangle.height)  // 出力:0

rectangle.height = 10
print(rectangle.height)  //出力:10

rectangle.height = 14
print(rectangle.height)  //出力:12

プロパティラッパーを使わなかった場合

NotUsingPropertyWrapper
import UIKit

var str = "Hello, playground"

struct TwelveOrLess {
    private var number: Int
    init(){self.number = 0}
    var wrappedValue:Int {
        get {return number}
        set {number = min(newValue, 12)} // 上限値を12とする
    }
}

struct SmallRectangle {
    private var _height = TwelveOrLess()
    private var _weight = TwelveOrLess()
    var height: Int{
        get {return _height.wrappedValue}
        set {_height.wrappedValue = newValue}
    }
    var weight:Int {
        get {return _weight.wrappedValue}
        set {_weight.wrappedValue = newValue}
    }
}

var rectangle = SmallRectangle()
print(rectangle.height)  // 出力:0

rectangle.height = 10
print(rectangle.height)  //出力:10

rectangle.height = 14
print(rectangle.height)  //出力:12

このように、複数のプロパティに対して同様な処理を行いたい場合などでは、コードをすっきりさせることができます!

今回記事で触れた部分はごく一部に過ぎず、プロパティラッパーはまだまだ奥が深いです。
もっと詳しく勉強したい方はプロポーザルを見ることをお勧めします!
プロパティラッパーのプロポーザル

型自身に紐づく タイププロパティ(スタティックプロパティ・クラスプロパティ)

インスタンスプロパティ・スタティックプロパティ・クラスプロパティ

  • インスタンスプロパティ:インスタンスのプロパティにアクセス
  • スタティックプロパティ:staticキーワードを用いることで、その型自身とプロパティを紐付ける。サブクラスでオーバーライドは不可能
  • クラスプロパティ:classキーワードを用いることで、クラス自身に紐付ける。サブクラスでオーバーライドが可能
instanceProperty
struct staticProperty {
 var name: String = "Aさん" // インスタンスプロパティ
 static var name2:String = "Bさん"  //スタティックプロパティ
}

let staticPropertyInstance = A()
print(staticPropertyInstance.name)  //出力:Aさん
print(staticProperty.name) //エラー

print(staticPropertyInstance.name2)  //エラー
print(staticProperty.name2)  //出力:Bさん

class classProperty {
  var name:String = "Cさん"  //インスタンスプロパティ
  class var name2:String = "ClassCさん"  //クラスプロパティ
}

let classPropertyInstance = classProperty()
print(classPropertyInstance.name)  //Cさん
print(classProperty.name)  //エラー

print(print(classPropertyInstance.name2)  //エラー
print(classPropertyInstance.name2)  //ClassCさん

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6