Swiftプロパティ(Properties)の詳細

8669 ワード

  • プロパティは、値を特定のクラス、構造、または列挙に関連付けます.
  • 記憶および計算属性は、通常、特定のタイプのインスタンスに関連付けられる.しかし、属性はタイプ自体に関連付けることもできます(クラス属性).
  • は、属性が定数と変数の値をインスタンスに格納し、計算属性がインスタンスの属性値を計算することを格納する.
  • 計算属性は、クラス、列挙、構造体によって提供される.ストレージ属性はクラスと構造体のみで提供されます.
  • プロパティオブザーバは、プロパティ値の変更を監視します.

  • 一、記憶属性

  • ストレージ属性は、特定のクラスまたは構造インスタンスの一部として格納される定数または変数である.
  • に格納される属性は、変数格納属性(var)であってもよいし、定数格納属性(let)であってもよい.
  • は、記憶属性の定義の一部としてデフォルト値を提供することができる.
  • は、初期化中に記憶属性の初期値を設定および変更することができ、定数記憶属性であってもよい.
  • struct FixedLengthRange {
        var firstValue: Int
        let length: Int
    }
    var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
    // the range represents integer values 0, 1, and 2
    rangeOfThreeItems.firstValue = 6
    // the range now represents integer values 6, 7, and 8
    

    (一)定数構造体インスタンスの記憶属性
  • 構造体は値タイプです.値タイプのインスタンスが定数としてマークされている場合、そのすべてのプロパティも定数としてマークされます.
  • 構造を作成したインスタンスを定数に割り当てると、変数属性として宣言する場合でも、インスタンスの属性は変更できません.
  • let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
    // this range represents integer values 0, 1, 2, and 3
    rangeOfFourItems.firstValue = 6
    // this will report an error, even though firstValue is a variable property
    

    (二)怠惰ロードストレージ属性
  • リロードストレージ属性は、属性宣言の前にlazy修飾子を追加して表される.
  • リロードストレージ属性は、最初の使用時にのみその初期値を計算します.
  • プロパティの初期値が外部要因に依存する場合、インスタンスの初期化が完了した後に知られる怠惰ロードプロパティを使用します.
  • プロパティの初期値が複雑または計算コストの高い設定を必要とする場合、必要でない限り、これらの設定を実行するべきではありません.
  • class DataImporter {
        /*
        DataImporter is a class to import data from an external file.
        The class is assumed to take a nontrivial amount of time to initialize.
        */
        var filename = "data.txt"
        // the DataImporter class would provide data importing functionality here
    }
    
    class DataManager {
        lazy var importer = DataImporter()
        var data = [String]()
        // the DataManager class would provide data management functionality here
    }
    
    let manager = DataManager()
    manager.data.append("Some data")
    manager.data.append("Some more data")
    // the DataImporter instance for the importer property has not yet been created
    
    print(manager.importer.filename)
    // the DataImporter instance for the importer property has now been created
    // Prints "data.txt"
    
    リロード属性は、インスタンスの初期化が完了した後にのみその初期値が取得されるため、変数として宣言する必要があります.定数プロパティは、初期化が完了する前に値を割り当てる必要があります.したがって、怠け者として宣言することはできません.複数のスレッドが初期化されていない怠惰なロード属性に同時にアクセスする場合、その属性が一度だけ初期化されることは保証されません.
    (三)属性とインスタンス変数を格納する
  • Objective-C言語では、属性に加えて、インスタンス変数を属性に格納された値のバックアップストレージとして使用することもできます.
  • Swift属性には対応するインスタンス変数がなく、属性のバックアップストレージに直接アクセスしません.

  • 二、計算属性

  • クラス、構造体、列挙で計算属性を定義することができ、計算属性は値を格納しない.
  • 計算属性は、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)
    print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
    // Prints "square.origin is now at (10.0, 10.0)"
    

    (一)簡潔なSetterメソッド宣言
  • 属性を計算するsetterメソッドに新しい値の名前が定義されていない場合は、デフォルトの名前newValueが使用されます.
  • 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メソッドはありません.
  • 
    struct Cuboid {
        var width = 0.0, height = 0.0, depth = 0.0
        var volume: Double {
            return width * height * depth
        }
    }
    let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
    print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
    // Prints "the volume of fourByFiveByTwo is 40.0"
    
    

    三、属性観察者

  • 属性の中でwillSetあるいはdidSetの観察者を定義して、属性値の変化を観察して応答する:(1).willSetは値を格納する前に呼び出されます.(2). didSetは、新しい値が格納された直後に呼び出される.
  • willSetのデフォルトのパラメータ名はnewValueであり、didSetのデフォルトのパラメータ名はoldValueである.
  • プロパティに新しい値を設定するたびに、プロパティの新しい値が現在の値と同じであっても、プロパティオブザーバーが呼び出されます.
  • は、任意の記憶属性に属性観察者を追加することができ、怠惰な記憶属性を除く.
  • は、サブクラスで属性を書き換えることによって、継承された属性(記憶属性または計算属性)に属性観察者を追加することができる.
  • 
    class StepCounter {
        var totalSteps: Int = 0 {
            willSet(newTotalSteps) {
                print("About to set totalSteps to \(newTotalSteps)")
            }
            didSet {
                if totalSteps > oldValue  {
                    print("Added \(totalSteps - oldValue) steps")
                }
            }
        }
    }
    let stepCounter = StepCounter()
    stepCounter.totalSteps = 200
    // About to set totalSteps to 200
    // Added 200 steps
    stepCounter.totalSteps = 360
    // About to set totalSteps to 360
    // Added 160 steps
    stepCounter.totalSteps = 896
    // About to set totalSteps to 896
    // Added 536 steps
    
    

    四、グローバル変数とローカル変数


    上述した属性の計算および観察のための機能は、グローバル変数およびローカル変数にも使用できます.グローバル変数は、任意の関数、メソッド、閉パッケージ、またはタイプコンテキストの外で定義される変数です.ローカル変数は、関数、メソッド、または閉パッケージコンテキストで定義された変数です.前の章で出会ったグローバル変数とローカル変数は、いずれも格納変数です.格納されたプロパティなどの格納変数は、特定のタイプの値に格納され、値の設定と取得を許可します.ただし、計算変数をグローバルまたはローカルの範囲で定義し、格納変数のオブザーバを定義することもできます.計算変数は、計算プロパティと同じように記述されるのではなく、値を計算します.

    五、クラス属性

  • クラス属性はクラス自体に属し、いくつかのインスタンスが作成されても、これらの属性は1つのコピーしかありません.
  • ストレージクラス属性は変数または定数として宣言することができ、計算クラス属性は変数として宣言するしかない.
  • ストレージクラス属性は、タイプ自体に初期化器がなく、初期化時にストレージクラス属性に値を付与できないため、デフォルト値を設定する必要があります.
  • ストレージタイプ属性は、最初のアクセス時にのみ不活性に初期化される.これらは、複数のスレッドが同時にアクセスしてもlazy修飾子タグを使用する必要がなく、一度だけ初期化されることを保証することができる.

  • (一)クラス属性文法
  • staticキーワードを使用してタイプ属性を定義します.
  • クラスの計算タイプ属性についてclassキーワード宣言を使用することができ、これにより、サブクラスが親クラスの実装を書き換えることを可能にすることができる.
  • struct SomeStructure {
        static var storedTypeProperty = "Some value."
        static var computedTypeProperty: Int {
            return 1
        }
    }
    enum SomeEnumeration {
        static var storedTypeProperty = "Some value."
        static var computedTypeProperty: Int {
            return 6
        }
    }
    class SomeClass {
        static var storedTypeProperty = "Some value."
        static var computedTypeProperty: Int {
            return 27
        }
        class var overrideableComputedTypeProperty: Int {
            return 107
        }
    }
    

    (二)クエリーと設定タイプ属性
  • タイプ属性の操作では、タイプのみを使用して値を問合せおよび設定できます.
  • print(SomeStructure.storedTypeProperty)
    // Prints "Some value."
    SomeStructure.storedTypeProperty = "Another value."
    print(SomeStructure.storedTypeProperty)
    // Prints "Another value."
    print(SomeEnumeration.computedTypeProperty)
    // Prints "6"
    print(SomeClass.computedTypeProperty)
    // Prints "27"
    
    struct AudioChannel {
        static let thresholdLevel = 10
        static var maxInputLevelForAllChannels = 0
        var currentLevel: Int = 0 {
            didSet {
                if currentLevel > AudioChannel.thresholdLevel {
                    // cap the new audio level to the threshold level
                    currentLevel = AudioChannel.thresholdLevel
                }
                if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                    // store this as the new overall maximum input level
                    AudioChannel.maxInputLevelForAllChannels = currentLevel
                }
            }
        }
    }
    
    var leftChannel = AudioChannel()
    var rightChannel = AudioChannel()
    
    leftChannel.currentLevel = 7
    print(leftChannel.currentLevel)
    // Prints "7"
    print(AudioChannel.maxInputLevelForAllChannels)
    // Prints "7"
    
    rightChannel.currentLevel = 11
    print(rightChannel.currentLevel)
    // Prints "10"
    print(AudioChannel.maxInputLevelForAllChannels)
    // Prints "10"
    

    六、その他のテーマモジュール


    Swift 4.2基礎テーマの詳細