[Swift]クラス——属性

15459 ワード

Swift言語では、包括的なオブジェクト向けのサポートが提供されています.まずクラス定義をサポートします.クラスでは、さまざまなタイプのメソッドと属性を定義できます.アクセス修飾子を設定することで、外部に表示されるメンバーとメソッド、非表示のメソッドを制御し、クラスのカプセル化を実現できます.
同時に1つのクラスまたは複数のクラスを継承し、クラスの継承性を実現することもできます.プロトコルという概念もあり、他のプログラミング言語のインタフェースに等しい.プロトコルはクラスと同じでも違います.
  • と同じ点:拡張を継承することができ、プロトコル自体も他のプロトコルを継承することができます.
  • の違い:プロトコルは属性をサポートせず、方法も宣言するしかなく、実現しない.プロトコルは独立して見ても,あるオブジェクトにインスタンス化することはできない.すなわち,プロトコルは実装プロトコルと呼ばれる特定のクラスを継承する必要がある.プロトコルが実装されたら、クラスにプロトコルを遵守または適合させる.

  • 一、最初のクラスの作成


    クラスはある物事の抽象であり、抽象を通じて一つの物事の特徴を定義し、通常、クラスは物事の属性と行為を定義している.プログラム上,クラス時に将来使用する具体的なオブジェクトのコードテンプレートを生成する.
    class Person {
        // 、 
    }
    /* Swift ,Person , class , , 、 、 , 。*/

    その主体は空であり、実際の用途はありませんが、クラスの最も簡単な定義を完了し、クラスを定義し、新しいデータ型を定義しました.このクラスは空クラスと呼ばれ、空クラスも呼び出すことができます.
    var p = Person()
    println(p)

    上のコードの中で、Pはオブジェクトで、Personクラスの具体化で、クラスはオブジェクトのテンプレートで、1つのクラスを定義して、無数のオブジェクトを生成することができます.オブジェクトを生成するプロセスをクラスのインスタンス化と呼びます

    1、属性


    属性とは、クラスが表す現実オブジェクトの特性をコードに反映することである.例えば、現実には学生という身分カテゴリがあり、先輩の属性には名前、クラス、出身地があり、対応する内容をクラスコードに対応すればよい.
    class Student{
        var name:String = ""       
        var classno:Int = 0
        var from:String = ""
    }
    class Student{
        var name:String = ""        // 
        var classno:Int = 0
        var from:String = ""
        let country:String = " " // 
    }
    
    var student = Student()
    
    student.name = "HTX"
    student.classno = 1
    student.from = "NanTong"
    
    println("\(student.name) \(student.classno) \(student.from)")
    
    // :HTX 1 NanTong

    Swift言語では、属性のタイプはストレージ属性と計算属性の2つに分けられます.
    ストレージ・プロパティは、クラスを表すプロパティです.計算数学自体は特性を直接記憶するものではなく,計算後の結果を提供する.

    1.1、記憶属性


    変数と同様に、属性も変数属性と定数属性に分けられ、格納属性と呼ばれ、キーワードvarとキーワードletでそれぞれ記述される.前の例ではname,classno,fromが変数属性でありcountryは定数属性である.
    以下の3つの注意点:(1)属性を定義する際に、属性ごとにデフォルト値を定義する必要があります.もちろん、初期化時に属性の初期値を設定することもできます.初期化もデフォルト値を定義しない場合はsuperを呼び出す.Init()でエラーが発生したり、オブジェクトが宣言された後も、強制パケット解除オプションとして明確に定義されていない限り、変数に値を割り当てることはできません.強制解除オプション:
    class StudentOptional{
        var name:String!
        var classno:Int!
        var from:String!
        let country:String!
    }
    var studentOptional = StudentOptional()
    studentOptional.name = "HTX"
    studentOptional.classno = 2
    studentOptional.from = "RuGao"

    (2)もう一つ注意すべき点は,記憶属性の定数属性であり,定数属性は絶対に変化してはいけないという意味ではなく,状況に応じて,記憶属性の定数属性が文字列,構造体などの値タイプであれば,これ以上変化することはできず,構造体の属性もこれ以上変化することはできない.クラスであれば、再割り当てが可能です.
    class Person{
        var name:String!
    }
    
    class StudentOptional{
        var name:String!
        var classno:Int!
        var from:String!
        let country:String = "china"
        let friend:Person = Person()
    }
    var studentOptional = StudentOptional()
    studentOptional.name = "HTX"
    studentOptional.classno = 2
    studentOptional.from = "RuGao"
    
    // 
    //studentOptional.country = " "
    
    // 
    studentOptional.friend.name = "HeTianXiong"

    (3)前述したように、ストレージ属性は一般的に初期化を要求しており、属性宣言時にこの初期化上の定義をしたにもかかわらず、lazy修飾子を設定することができる.修飾子とは、変数、関数、クラスなどの定義の前に接頭辞を付けて、変数、関数、クラスの機能を制約または強化するための特殊なキーワードです.
    Lazy修飾のストレージ属性は、怠惰なストレージ属性と呼ばれます.怠惰なストレージ属性は、最初に使用されたときに初期値計算されます.たとえば、インスタンスの初期化が完了する前に外部の理由でプロパティの初期値が確定しない場合は、怠惰なストレージプロパティとして定義します.プロパティの初期値に複雑または高コストの設定が必要で、必要に応じて割り当てられると、怠惰なプロパティが役立ちます.
    class Deposit{
        init(){
            println("init at deposit")
        }
    }
    
    class PersonLazy {
        var name:String!
        lazy var money:Deposit = Deposit()
    }
    
    class StudentLazy{
        var name:String!
        var classno:Int!
        var from:String!
        let country:String = "china"
        let friend:PersonLazy = PersonLazy()
    }
    
    var studentlazy = StudentLazy()
    studentlazy.name = "HTX"
    studentlazy.classno = 1
    studentlazy.from = "suzhou"
    studentlazy.friend.name = "huhu"

    このようにlazyプロパティが定義されているため、「init at deposit」は出力されません.この例では使用されていないため、付与計算はありません.lazyの修飾がなければ、この文は上のコードのすべての出力の前に出力されます.
    怠惰属性は、インスタンスの初期化が完了するまで呼び出されない初期値が計算されるため、インスタンスの初期化が完了する前に定数属性が付与されるべきであるため、定数属性は怠惰属性として宣言できないため、変数属性が必要であることは容易に理解できます.

    1.2、計算属性


    計算プロパティは、他のプログラミング言語で一般的にメンバー関数またはメソッドの形式で表示されます.もちろんSwiftでも利用できますが、より柔軟な選択肢を提供します.計算プロパティは直接データを保存することはできませんが、getterとsetterを使用して間接的に他のプロパティと値を取得または変更できます.
    まず簡単な計算機を作ります:1、方法で実現します
    class Calculator {
        var a:Int = 1
        var b:Int = 1
        init(a:Int,b:Int){
            self.a = a
            self.b = b
        }
    
        func sum()->Int {
            return a + b
        }
    
        func quotient()->Int{
            return a/b
        }
    
        func product()->Int{
            return a * b
        }
    
        func difference()->Int {
            return a - b
        }
    }

    2、計算方式で実現する:
    class PCalculator {
        var a:Int = 1
        var b:Int = 1
        var sum:Int{
            return a + b
        }
    
        var difference:Int{
            return a - b
        }
    
        var product:Int{
            return a * b
        }
    
        var quotient:Int {
            return a/b
        }
        init(a:Int,b:Int){
            self.a = a
            self.b = b
        }   
    }

    計算プロパティは変数値を直接保存するわけではありませんが、値を設定することで他のプロパティ値を変更することができます.便利なのは、前の例にscale計算プロパティを追加することです.scale自体は保存する必要はありません.2つの値を等比的に拡大するために使用されます.もちろん他の計算属性の値も変化します.
    class PCalculator {
        var a:Int = 1
        var b:Int = 1
        var sum:Int{
            return a + b
        }
    
        var difference:Int{
            return a - b
        }
    
        var product:Int{
            return a * b
        }
    
        var quotient:Int {
            return a/b
        }
        init(a:Int,b:Int){
            self.a = a
            self.b = b
        }
        var scale:Int{
            get{
                return a/a
            }
            set{
                a = a * newValue
                b = b * newValue
            }
        }
    }
    
    var pcal = PCalculator(a: 30, b: 10)
    pcal.scale = 3
    println("\(pcal.sum) \(pcal.quotient) \(pcal.product) \(pcal.difference)") // :120 3 2700 60

    計算プロパティには、次の2つの注意事項があります.
  • 1、計算プロパティ(読み取り専用計算プロパティを含む)は、varキーを使用する必要があります.値が固定されていないためです.letキーワードは定数属性のみで使用され、letで計算属性を定義するとコンパイラがエラーを報告します.
  • 2、計算プロパティを使用するには、必ずタイプを宣言してください.そうしないと、エラーが発生します.

  • 1.3、属性観察者


    プロパティ・オブザーバーでは、個人的な理解はトリガのようなもので、データベースにはトリガの概念があり、ある操作が発生すると、別のプリセットされた操作がトリガーされ、あるイベントがトリガーされる前または後に呼び出されるコールバック関数にも似ています.
    ただし、プロパティオブザーバとトリガが異なるのは、プロパティが変更される前にトリガすることもできます!プロパティオブザーバは、プロパティ値の変化を観察し、これに応答します.プロパティの値を設定すると、プロパティオブザーバが呼び出され、新しい値が元の値と同じ場合でも呼び出されます.怠惰なストレージ属性に加えて、任意のストレージ属性に属性オブザーバ定義を加えることができます.また、サブタイプ属性を書き換えることで、属性(格納または計算)に属性オブザーバ定義を加えることもできます.
    2048ゲームでは、属性観察者定義が用いられ、具体的にはポイントパネルで、ゲームをするときに点数を変更するが、ポイントパネルには点数だけでなく、他の文字もあり、普通点と最高点の2つの積分があり、毎回点数を変更するたびにパネルの数字も変化する.
    var label:UILabel!
    var stype:String! // 
    
    var score:Int = 0{
        didSet{
            // , 
            label.text = "\(stype):\(score)"
        }
    }

    属性観察者も過去のクラス挙動の最適化である.他の言語では、上記のコードは次のようになります.
    var label:UILabel!
    var stype:String! // 
    
    var score:Int = 0
    func setScore(score:Int){
        didSet{
            self.score = score
            // , 
            label.text = "\(self.stype):\(self.score)"
        }
    }

    上記のコードはscoreのためにsetter関数を設計し,付与するたびに更新ラベル上のテキストを関連付け,悪い点をもたらし,属性更新と他のインタフェース表現操作を結合し,属性観察者の使用がより簡潔であることがわかる.
    プロパティ・オブザーバでは、次の点に注意してください.
  • 1、属性にオブザーバーを追加するには、属性タイプを明確に宣言する必要があります.そうしないと、コンパイラは
  • をエラーします.
  • 2、willSetはnewNameのパラメータを持つことができ、そうでなければ、属性を計算する漢方病院がこのパラメータを買うようにデフォルトのnewValueになります.
  • 、didSetはまた、古い属性を表すoldNameのパラメータを1つ残してもよく、持たない場合、このパラメータはデフォルトでoldValueと命名されます.
  • 4、属性初期化時にwillSetおよびdidSetは呼び出されず、初期化コンテキスト以外でのみ、属性設定時に
  • が呼び出される.
  • 5、willSer、didSetは、設定された値が元の値と同じであっても、設定された属性値のたびに呼び出されます.
  • var stype:String! // 
    
    var score:Int = 0{
        willSet{
            // , 
            label.text = "\(stype):\(newValue)"
        }
    }

    1.4、タイプ属性


    インスタンス・プロパティは、特定のクラス・インスタンスのプロパティです.クラスインスタンスを作成すると、このインスタンスには独自のプロパティ値のセットがあり、他のインスタンスとは区別され、各クラスインスタンスには独自のストレージスペースがあり、これらのインスタンスのプロパティにも独自のストレージスペースがあります.
    ただし、クラスのインスタンスではなく、オブジェクトではない属性を定義することもできます.このクラスのインスタンスをいくら作成しても、このプロパティはいずれにも属しず、クラス自体にのみ属します.このようなプロパティをタイププロパティと呼びます.タイププロパティは、別の言語でクラス静的変数と呼ばれます.
    タイプ属性はグローバル変数に似ています.定義後に直接使用できますが、グローバル変数はクラスに依存せずに存在し、タイプ属性はクラスに依存して存在するため、呼び出し時にクラス接頭辞を追加し、クラスのアクセスレベルに制限する必要があります.
    タイプ属性定義の方法は簡単です.クラスで定義するときは、変数キーワードvarの前にclassキーワードを直接追加し、get関数の設定方法で変数の値を返します.直接値を割り当てることはできません.
    class Teacher {
        var name:String!
        var classno:Int!
        var from:String!
        class var country:String{
            return " "
        }
    }
    
    println(Teacher.country)
    // : 

    ===================================================