Swift-属性関連

5787 ワード

一、記憶属性


コンセプト:ストレージ属性は、特定のクラスまたは構造体インスタンスに格納される定数または変数です.
注意:1列挙では使用できません2クラスを上書きすることはできませんが、サブクラスで属性観察を行うことができます

1.1定数記憶属性(let定義)

let id: Int

1.2変数格納属性(var定義)

var name: String

1.3遅延ストレージ属性(lazy定義、怠惰ロード)

lazy var :   = {   }()

二、計算属性


コンセプト:計算プロパティは値を直接格納するのではなく、getterとオプションのsetterを提供し、他のプロパティまたは変数の値を間接的に取得および設定します.
注意:letで計算プロパティを修飾することはできません

2.1完全な書き方

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)
        }
    }
}

長方形の中心点は原点(origin)とサイズ(size)から算出できるので、明示的に宣言されたPointで保存する必要はありません.Rectの計算プロパティcenterは、格納プロパティがあるように矩形の中心点を取得および設定するためにカスタムgetterおよびsetterを提供します.

2.2 setterの書き方の簡略化


計算属性のsetterに新しい値を表すパラメータ名が定義されていない場合は、デフォルト名(newValue)を使用します.
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 {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

2.3読取り専用計算属性


getterのみ、setterのない計算プロパティは読み取り専用計算プロパティです.新しい値は設定できません.
var name: String {
    return  “Rose"
}

三、属性オブザーバ


コンセプト:新しい値と現在の値が同じ場合でも、プロパティオブジェクトはプロパティが設定されるたびに呼び出されます.
class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
            print("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {
            if totalSteps > oldValue  {
                print("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

もちろん、willSetの後のパラメータ名は省略できますが、デフォルトの(newValue)で代用します.

四、関連問題


4.1 setとwillSet、didSetが共存?


同じタイプでは,属性観測と計算は同時に共存できないことを知った.すなわち,1つの属性定義にsetとwillSetまたはdidSetを同時に出現させることは不可能である.計算属性ではsetの内容を書き換えることでwillSetやdidSetと同様の属性観察の目的を達成することができる.このクラスを変更できず、属性観察で何かをしようとすると、このクラスをサブクラス化し、その属性を書き換える必要があるかもしれません.書き換えられた属性は、親属性の具体的な実装を知らず、名前とタイプのみが親属性から継承されるため、親属性が格納されているか計算されているかを気にすることなく、子のリロード属性に親属性の属性を任意に追加できます.
class A {
    var number :Int {
        get {
            print("get")
            return 1
        }
        set {print("set")}
    }
}
class B: A {
    override var number: Int {
        willSet {print("willSet")}
        didSet {print("didSet")}
    }
}

numberのsetメソッドを呼び出すと、作業の順序が表示されます.
let b = B()
b.number = 0

//  
// get
// willSet
// set
// didSet

setと対応する属性観察の呼び出しはいずれも我々の予想通りである.ここで注意したいのはgetが最初に呼び出されたことです.これは、didSetを実現したためです.didSetではoldValueが使用されますが、この値はset動作全体の前に取得して保存する必要があります.そうしないと、正確性が確保されません.私たちがdidSetを実現しなければ、今回のget操作も存在しません.

4.2タイプ属性(静的属性)


Swiftでは、タイプ属性はタイプ定義の一部であり、タイプの最外層カッコ内に書かれており、役割ドメインはこのタイプがサポートする範囲内である.キーワードstaticでタイプ属性を定義する
struct AssociatedKeys {
    static var managerKey = “key"
}

4.3 staticとclass


クラスにとってstaticまたはclass修飾子を使用することは可能です.これらの使用後の効果は同じですが、本質的には異なります.1 classはクラスでしか使用できません.staticはクラス、構造体、列挙で2 staticを使用してクラスに適用できますが、実はclass finalの別名3 static修飾の属性や関数は書き直すことはできません.しかしclass修飾は4 classを書き換えることができて記憶属性を修飾することができません
class MyClass {
    class var bar: Int = 0
}
//  
class variables not yet supported

4.4属性観察とinout

class Circle{
   lazy var area: Double = 0.0
    var r:Double = 0.0 {
        willSet{
            print(" ")
            area = Double.pi*newValue*newValue
        }
    }
}
let circle = Circle()
func calcalate(r:inout Double){
   print(" ")
   r = 2.0
  print(" ")
}
calcalate(r: &circle.r)

//  :
//  
//  
//  
 r 2,area 12.5663

結論:関数のパラメータがinout修飾されている場合、モニタリングの属性をこの関数に入力すると、属性の値がコピーされ、関数が終了すると、値が属性に再支払われるため、関数の実行が完了すると、モニタリング関数がトリガーされます

4.5パラメータ初期化


4.5.1パラメータは閉パケット実行の結果である:定数を宣言した後、一つの直後の閉パケットで初期化を行う
let purpleView: UIView = {
    let view = UIView()
    view.backgroundColor = UIColor.purple
    return view
}()
//  
let purpleView: UIView = iniPurpleView()
    
func iniPurpleView() -> UIView {
    let view = UIView()
    view.backgroundColor = UIColor.purple
    return view
}

4.5.2目立つ書き方
let purpleView: UIView = {
    $0.backgroundColor = UIColor.purple
    return $0
}(UIView())

この書き方は,閉パケットで変数に名前を付ける悩みを省くことができ,コードもよりコンパクトになる.もちろん后ろにはもっと可読性の高い书き方もありますが、NSObjectに対してextensionを书く必要があります.兴味があれば、SwitGG-目の前を明るくする初期化方法を知ることができます.

4.6怠惰ロードとパラメータ初期化、計算属性区分


3つの書き方の違いと呼び出しのタイミングに注意
class Person {
    var name: String = {
        print(" ")
        return "YY"
    }()
    lazy var lastName: String = {
        print(" ")
        return "YANG"
    }()
    var age: Int { //  
        print("AGE")
        return 20
    }
}

次にPerson変数をインスタンス化します
let p = Person()
//  , 

締めくくり:後で属性に関する質問があったら補足し続けますので、間違いがあったら指摘してください^^
参考文献:Swift公式文書Swift 3.0-属性-酷走天涯属性観察-王巍(@ONEVCAT)