[Swift]「計算プロパティ」

この記事では、計算プロパティ(Computed Properties)について、具体的なコード例や使い方を通じて、基本から応用までを解説します。

参考にした講座

iOS & Swift – The Complete iOS App Development Bootcamp (Udemy)
 (Section21) Advanced Swift Classroom – Part1

目次

計算プロパティの基礎

計算プロパティ(Computed Propertiesは、値を計算して提供するプロパティです。これにより、値の計算や加工を自動化し、便利な機能を実現することができます。

基本的な使い方

コード事例
struct Circle {
    var radius: Double
    
    var area: Double {
        return Double.pi * radius * radius
    }
}

var myCircle = Circle(radius: 5.0)
print(myCircle.area) 
// 結果: 78.53981633974483
  • 上記の例では、Circleという構造体を定義しました。
  • Circleにはradiusという格納プロパティと、areaという計算プロパティがあります。
  • areaは、円の面積を計算して提供する計算プロパティです。
    radiusを使用して円の面積を計算し、結果を返します。

上記の例では、myCircleというインスタンスを作成し、その面積を表示しています。
計算プロパティは、実際に値が参照されるまで計算されないため、areaの値が必要な時に自動的に計算されます。

これにより、面積を手動で計算する必要がなくなり、コードがシンプルで読みやすくなります。

計算プロパティと格納プロパティの違い

計算プロパティ(Computed Properties格納プロパティ(Stored Propertiesの2つのプロパティの種類があります。それぞれの違いと使い分けについて解説します。

計算プロパティは、値を計算して提供するプロパティです。
そのため、値は保持されず、必要に応じて計算されます。計算プロパティは、動的な値の提供やデータの変換など、値の計算や加工が必要な場合に使用されます。

格納プロパティは、値を保持して提供するプロパティです。
値はインスタンスによって保持され、インスタンスのライフサイクルを通じて使用されます。

以下に、具体的なコード事例を示します。

プロパティの種類と使い分け
struct Circle {
    var radius: Double // 格納プロパティ
    var color: String // 格納プロパティ

    var area: Double { // 計算プロパティ
        return Double.pi * radius * radius
    }

    var diameter: Double { // 計算プロパティ
        return radius * 2
    }
     
    init(radius: Double, color: String) {
        self.radius = radius
        self.color = color
    }
}

var myCircle = Circle(radius: 5.0, color: "Red")
print(myCircle.area) 
// 結果: 78.53981633974483

print(myCircle.diameter) 
// 結果: 10.0

print(myCircle.color) 
// 結果: Red
  • 上記の例では、Circleという構造体を定義しています。
  • Circleには、以下のプロパティがあります。
  • radiuscolor格納プロパティであり、インスタンスによって保持されます。これは、円の色を表現するためのプロパティです
  • areadiameterは、計算プロパティであり、radiusを使用して円の面積や直径を計算します。

get-setの使い方

get-setは、計算プロパティ(Computed Properties)において使用されます。

getブロックはプロパティの値を取得するために使用され、setブロックはプロパティに新しい値を設定するために使用されます。getブロックは必須であり、setブロックは省略可能です。

get-setを使うことで、プロパティの値の計算や加工を自在に行うことができます。

get-setのコード事例
import UIKit

let pizzaInInchies: Int = 12

var numberOfSlices: Int {
    get {
        return pizzaInInchies - 4
    }
    set {
        print("numberOfSlices = \(newValue)")
        
    }
}

print("numberOfSlices = \(numberOfSlices)") 
// 結果: numberOfSlices = 8

numberOfSlices = 12 
// 結果: numberOfSlices = 12
  • このコードでは、numberOfSlicesという計算プロパティを定義しています。
  • getブロックでは、pizzaInInchiesから4を引いた値を返します。
  • setブロックでは、新しい値を受け取って印刷します。
  • 最初のprintステートメントでは、numberOfSlicesの値を取得して表示します。
    getブロックが実行され、pizzaInInchiesから4を引いた結果である8が表示されます。
  • numberOfSlicesに新しい値12を設定します。
    この値がsetブロックに渡され、”numberOfSlices = 12″というメッセージが出力されます。

データ変換とバリデーションへの応用

計算プロパティを使ってデータの変換バリデーションを行う方法について解説します。これにより、入力データを必要な形式に変換したり、制約を適用してデータの整合性を確保したりすることができます。

データ変換とバリデーションへの応用
struct Temperature {
//摂氏:格納プロパティ
    var celsius: Double

//華氏:計算プロパティ    
    var fahrenheit: Double {
        get {
            return celsius * 9 / 5 + 32
        }
        set {
            celsius = (newValue - 32) * 5 / 9
        }
    }
}

//摂氏25を入力
var temperature = Temperature(celsius: 25)
print(temperature.fahrenheit) 
// 結果: 77.0

//華氏86を設定
temperature.fahrenheit = 86
print(temperature.celsius) 
// 結果: 30.0
struct Temperature
  • この構造体には、摂氏温度を表すcelsiusと、それに基づいて計算される華氏温度を表すfahrenheitという2つのプロパティがあります。
  • fahrenheitgetブロック
    celsiusの値を摂氏から華氏に変換して返します。
  • fahrenheitsetブロック
    新しい華氏温度の値が設定されると、その値を元にして摂氏温度を計算し、celsiusに設定します。
var temperature = Temperature(celsius: 25)
  • temperatureというTemperature構造体のインスタンスを作成し、初期の摂氏温度を25として設定します。
  • printステートメントによって、temperature.fahrenheitが表示されます。
  • この時、getブロックが実行され、celsiusの値が華氏温度に変換されて77.0が表示されます。
temperature.fahrenheit = 86
  • temperature.fahrenheit新しい値86を設定します。
  • この時、setブロックが実行され、新しい華氏温度から摂氏温度が再計算され、結果としてtemperature.celsiusに30.0が表示されます。

計算プロパティの応用

didSetの使い方

計算プロパティでは、プロパティへの値の設定や取得時に特定の処理を追加することができます。これにより、値の変更を監視したり、計算結果をキャッシュしたりすることができます。

以下に、具体的な例を示します。

didSetの使い方
struct Progress {
    var totalSteps: Int
    var completedSteps: Int {
        didSet {
            if completedSteps > totalSteps {
                completedSteps = totalSteps
            }
            if completedSteps < 0 {
                completedSteps = 0
            }
        }
    }
    
    var progressPercentage: Double {
        return Double(completedSteps) 
        / Double(totalSteps) * 100
    }
}

var progress = Progress(totalSteps: 10, 
    completedSteps: 5)

例1:
progress.completedSteps = 15
print(progress.completedSteps) 
// 結果: 10

例2:
progress.completedSteps = -2
print(progress.completedSteps) 
// 結果: 0

例3:
print(progress.progressPercentage) 
// 結果: 50.0
struct Progress
  • Progress構造体が定義されています。
  • この構造体には、総ステップ数を表すtotalStepsと、完了したステップ数を表すcompletedSteps、進捗率を計算するprogressPercentageの3つのプロパティがあります。

completedStepsdidSetブロックでは、completedStepsの値が変更された後に実行されます。このブロック内で、以下の2つの条件をチェックしています:

  1. completedSteps>totalStepsのとき
    completedStepstotalStepsに設定します。
  2. completedSteps<0のとき
    completedStepsを0に設定します。

これにより、completedStepsの値が範囲外になることを防ぎます。

例1:progress.completedSteps = 15
  • progressというProgress構造体のインスタンスを作成し、初期のtotalStepsを10、completedStepsを5として設定します。
  • progress.completedStepsに新しい値15を設定します。
  • この時、didSetブロックが実行され、completedSteps(15)>totalSteps(10)のため、値が制限されてcompletedStepsは10に設定されます。
例2:progress.completedSteps = -2
  • progress.completedStepsに新しい値-2を設定します。
  • didSetブロックが実行され、completedStepsが0未満であるため、値が制限されて0に設定されます。
例3:print(progress.progressPercentage)
  • progress.progressPercentageが表示されます。
  • この時、進捗率の計算が行われ、completedSteps(5)/totalSteps(10)により、結果として50.0が表示されます。

willSet-didSet

willSet-didSetは、格納プロパティにおいて使用されます。

willSetブロックは、プロパティに新しい値が設定される直前に呼び出され、didSetブロックプロパティに新しい値が設定された直後に呼び出されます。willSetとdidSetブロックは共に省略可能です。

willSet-didSetを使うことで、プロパティの値の変更を監視し、特定の処理を追加することができます。

willSet-didSetのコード事例
import UIKit

let pizzaInInchies: Int = 12

var numberOfSlices: Int = 10 {
    willSet {
        print("willSet = \(numberOfSlices)")
        print("willSet:newValue = \(newValue)")
    }
    didSet {
        print("didSet = \(numberOfSlices)")
        print("didSet:oldValue = \(oldValue)")     
    }
}

print("numberOfSlices = \(numberOfSlices)") 
// 結果: numberOfSlices = 10

numberOfSlices = 12 

// 結果: 
// willSet = 10
// willSet:newValue = 12
// didSet = 12
// didSet:oldValue = 10
  1. このコードでは、numberOfSlicesという格納プロパティに対してプロパティオブザーバを使用しています。
  2. willSetブロックでは、新しい値が設定される直前に実行されます。
  3. didSetブロックでは、プロパティの値が変更された直後に実行されます。
  4. 最初のprintステートメントでは、numberOfSlicesの現在の値である10が表示されます。

次に、numberOfSlicesに新しい値12を設定します。

  1. この時、willSetブロックが実行され、現在の値10と新しい値12がそれぞれ表示されます。
  2. その後、didSetブロックが実行され、変更された値12と、変更前の値10が表示されます。

この記事が気に入ったら
いいね または フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次