Swift3.0-プロパティ、プロパティオブザーバ

7694 ワード

ツールバーの


プロパティは、値を特定のクラス、構造、または列挙に関連付けます.
ストレージのプロパティ
簡単に言えば、1つのストレージ属性は、特定のクラスまたは構造体インスタンスに格納される定数または変数です.記憶属性は、変数記憶属性(キーワードvarで定義)であってもよく、定数記憶属性(キーワードletで定義)であってもよい.
ストレージ属性を定義するときにデフォルト値を指定できます.また、構築中にストレージ属性の値を設定または変更することもできます.
struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
//  0,1,2
rangeOfThreeItems.firstValue = 6
//  6,7,8
FixedLengthRangeの例は、firstValueという変数記憶属性と、lengthという定数記憶属性とを含む.上記の例では、lengthはインスタンスの作成時に初期化され、定数記憶属性であるため、その後の値は変更できません.
定数構造体のストレージプロパティ
構造体のインスタンスを作成して定数に値を割り当てると、そのインスタンスのプロパティは変更できません.変数として宣言されたプロパティがあっても、変更できません.
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
//  0,1,2,3
rangeOfFourItems.firstValue = 6
//   firstValue  , 
rangeOfFourItemsが定数として宣言されているため(letキーワードで)、firstValueが変数属性であっても変更できません.
この挙動は構造体(struct)が値タイプに属するためである.値タイプのインスタンスが定数として宣言されると、そのすべてのプロパティが定数になります.
参照タイプに属するクラス(class)は異なります.参照タイプのインスタンスを定数に割り当てると、インスタンスの変数プロパティを変更できます.
遅延ストレージ属性(怠惰ロード)
遅延ストレージ属性とは、最初に呼び出されたときにその初期値が計算される属性です.属性宣言の前にlazyを使用して、遅延ストレージ属性を表示します.
注意:属性の初期値は、インスタンス構築が完了した後に得られる可能性があるため、遅延記憶属性は変数として宣言する必要があります(varキーワードを使用します).定数属性は、構築プロセスが完了する前に初期値が必要であるため、遅延属性として宣言できません.
遅延プロパティは、インスタンスの構築プロセスが終了してから値に影響する外部要因がわかるようにプロパティの値に依存する場合や、プロパティの初期値を取得するのに複雑または大量の計算が必要な場合にのみ計算できます.
class DataImporter {
    var fileName:String? = "data.txt"
    init() {
        print(" DataImporter")
    }
}

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

let manager = DataManager()
manager.importer.fileName = "fileName" // print:  DataImporter

OCでのダラダラロードはnilか否かを判断し、nilであれば作成するが、Swiftでlazyタグを用いた属性は初めてアクセスされたときのみ作成される.
注意lazyとマークされた属性が初期化されていない場合、同時に複数のスレッドにアクセスされる場合、その属性が一度だけ初期化されることは保証されません.
計算プロパティ
クラス、構造体、列挙は、ストレージ属性に加えて計算属性を定義できます.計算プロパティは、値を直接格納するのではなく、getterとオプションのsetterを提供して、他のプロパティまたは変数の値を間接的に取得および設定します.
struct Point { //  
    var x = 0.0, y = 0.0
}
struct Size { //  
    var width = 0.0, height = 0.0
}
struct Rect { //  
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set(newCenter) {
            origin.x = newCenter.x - (size.width / 2)
            origin.y = newCenter.y - (size.height / 2)
        }
    }
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
                  size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)

この例では、ジオメトリを記述する3つの構造体を定義します.
  • Pointは、(x, y)の座標
  • をカプセル化する.
  • Sizeは、1つのwidthおよび1つのheight
  • をカプセル化する.
  • Rectは、原点および寸法を有する矩形
  • を表す.Rectはまた、centerという計算属性を提供する.長方形の中心点は、原点(origin)およびサイズ(size)から算出できるので、明示的に宣言されたPointで保存する必要はない.Rectの計算プロパティcenterは、矩形の中心点を取得および設定するためのカスタムgetterおよびsetterを提供し、記憶プロパティがあるようにします.
    便利setter宣言
    計算属性のsetterが新しい値を表すパラメータ名を定義していない場合は、デフォルト名newValueを使用します.以下は、便利なsetter宣言を使用したRect構造体コードです.
    struct AlternativeRect {
        var origin = Point()
        var size = Size()
        var center: Point {
            get {
                let centerX = origin.x + (size.width / 2)
                let centerY = origin.y + (size.height / 2)
                return Point(x: centerX, y: centerY)
            }
            set {
                origin.x = newValue.x - (size.width / 2)
                origin.y = newValue.y - (size.height / 2)
            }
        }
    }
    

    読み取り専用計算プロパティ
    getterにsetterがない計算属性だけが読み取り専用計算属性です.読み取り専用計算プロパティは、ポイント演算子でアクセスできる値を常に返しますが、新しい値を設定することはできません.
    注意:値が固定されていないため、varキーワードを使用して計算プロパティを定義する必要があります.letキーワードは定数属性を宣言するためにのみ使用され、初期化後に変更できない値を示します.
    読み取り専用計算プロパティの宣言により、getのキーワードとカッコを削除できます.
    struct Cuboid {
        var width = 0.0, height = 0.0, depth = 0.0
        var volume: Double {
            // get {
                return width * height * depth
            // }
            
        }
    }
    let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
    print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
    //   "the volume of fourByFiveByTwo is 40.0"
    

    この例は、Cuboidwidth、およびheightの属性を含む3次元空間を表す立方体を定義する.構造体には、立方体のボリュームを返すためにdepthという読み取り専用計算プロパティもあります.volumeにsetterを提供することは、volumewidthheight、およびdepthの3つの値をどのように変更して新しいvolumeに一致するかを決定することができないため、意味がありません.しかしながら、Cuboidは、外部ユーザが直接ボリュームを取得するために読み取り専用計算属性を提供することが有用である.
    属性オブザーバ
    アトリビュートオブザーバは、アトリビュート値の変化を監視し、応答します.アトリビュート値が設定されるたびにアトリビュートオブザーバが呼び出されます.新しい値と現在の値が同じ場合でも例外ではありません.
    遅延ストレージ属性以外のストレージ属性に属性オブザーバを追加するか、継承した属性(ストレージ属性と計算属性を含む)を書き換えることで属性オブザーバを追加できます.書き換えられていない計算プロパティにプロパティオブザーバを追加する必要はありません.setterによって値の変化を直接監視し、応答することができます.
    アトリビュートに次の1つまたはすべてのオブジェクトを追加できます.
  • willSet新しい値が設定前に
  • が呼び出される.
  • didSetは、新しい値が設定された直後に
  • を呼び出す.willSetオブザーバは、新しい属性値を定数パラメータとして入力し、willSetのインプリメンテーションコードでこのパラメータの名前を指定できます.指定しない場合、パラメータは使用できます.この場合、デフォルトの名前newValueで表されます.
    同様に、didSetオブザーバは、古い属性値をパラメータとして入力し、このパラメータに名前を付けるか、デフォルトのパラメータ名oldValueを使用することができます.didSetメソッドでプロパティに再び値を割り当てると、新しい値は古い値を上書きします.
    親のプロパティが子クラスのコンストラクタに割り当てられている場合、親クラスのwillSetおよびdidSetオブザーバが呼び出され、その後、子クラスのオブザーバが呼び出されることに注意してください.親初期化メソッドが呼び出される前に、サブクラスがプロパティに値を割り当てると、オブザーバは呼び出されません.
    次に、willSetおよびdidSetが実際に使用された例を示し、StepCounterというクラスが定義され、1人の歩行時の総歩数を統計するために使用される.このクラスは、歩数計や他の日常的なトレーニングの統計装置の入力データと組み合わせて使用することができます.
    class StepCounter {
        var totalSteps: Int = 0 {
            willSet(newTotalSteps) {
                print("totalSteps   \(newTotalSteps)")
            }
            didSet {
                if totalSteps > oldValue  {
                    print("  \(totalSteps - oldValue)  ")
                }
            }
        }
    }
    let stepCounter = StepCounter()
    stepCounter.totalSteps = 200
    // print: totalSteps   200
    // print:   200  
    stepCounter.totalSteps = 360
    // print: totalSteps   360
    // print:   160  
    stepCounter.totalSteps = 896
    // print: totalSteps   896
    // print:   536  
    
    StepCounterクラスは、IntおよびtotalStepsオブザーバを含むストレージ属性であるwillSetタイプの属性didSetを定義する.totalStepsが新しい値を設定されると、willSetdidSetのオブザーバが呼び出され、新しい値と現在の値が完全に同じであっても呼び出されます.
    例のwillSetオブザーバは、新しい値を表すパラメータをnewTotalStepsにカスタマイズし、このオブザーバは単純に新しい値を出力するだけである.didSetオブザーバは、totalStepsの値が変更された後に呼び出され、新しい値と古い値を比較し、総ステップ数が増加した場合、どのくらい増加したかを示すメッセージを出力します.didSetは古い値にカスタム名を指定していないので、デフォルト値oldValueは古い値のパラメータ名を表します.
    に注意
    属性がin-out方式で関数に入力されると、willSetおよびdidSetも呼び出されます.これは、in-outパラメータがコピーコピーモードを採用しているためです.すなわち、関数内部でパラメータのcopyが使用され、関数が終了した後、パラメータに値を再割り当てします.
    func change( a: inout Int) {
        a += 1
    }
    change(a: &stepCounter.totalSteps)
    // totalSteps   897
    //   1