[Swift構文]9.Structures and Classe


SWIFTの公式文書の第9部「構造と資産」を読み、整理します.
SWIFT Apple公式文書第9章構造と資産

Structures and Classes


構造(構造体)とクラス(クラス)は、複数のpropertyとメソッドを同時に処理できる構造である.
他の言語とは異なり、swiftは構造体とクラスを作成し、個別のインタフェースと実装ファイルを作成する必要はありません.
ファイルに構造体とクラスが定義されている場合、外部インタフェースでは構造体とクラスが自動的に有効になります.

Comparing Structures and Classes


SWIFTの構造体とクラスには多くの共通点がある.

  • 値を格納するためにpropertyを宣言できます.

  • 関数機能を宣言する方法.

  • ルーラー構文を使用して内部値にアクセスできます.

  • ジェネレータを使用して初期状態を設定できます.

  • 基本的な実装に加えて、機能を拡張することもできます.

  • プロトコルを使用して標準機能を提供できます.
  • クラスには構造体にない機能があります.

  • 1つのクラスは、別のクラスのプロパティの継承をサポートします.

  • タイプ選択により、実行時にクラスインスタンスのタイプを決定できます.

  • Deinitializerを使用してクラスインスタンスの割り当てを解除します.

  • クラスインスタンスの2つ以上の参照数(参照回数)を許可します.
  • これらのクラスのみをサポートする機能は複雑さを増します.
    だから一般的に構造体が好きで、これらの機能が必要なときにクラスを使います.実際には、ほとんどのカスタムデータフォーマットは構造体と列挙型です.

    Definition Syntax


    構造体とクラスは、同様に宣言できます.構造体はstructキーワード、クラスはclassキーワードを使用します.
    struct Resolution {
        var width = 0
        var height = 0
    }
    class VideoMode {
        var resolution = Resolution()
        var interlaced = false
        var frameRate = 0.0
        var name: String?
    }
    このように構造体やクラスを宣言する場合は,SWIFTのスタイルに従うことが望ましい.
    クラスまたは構造体は大文字で始まるのが好ましく、その方法またはプログラムは小文字で始まるのが望ましい.
    上記のコードで変数または定数を宣言する方法は、既存の方法と同じです.resolution変数はResolution構造体インスタンスを作成します.

    Structure and Class Instances


    上で定義したResolutionまたはVideoModeは、実際に使用した値ではなく、構造体とクラスの形状のみを定義します.定義された構造体とクラスを使用するには、インスタンスを作成して使用する必要があります.
    let someResolution = Resolution()
    let someVideoMode = VideoMode()
    インスタンスを作成する方法は、上記のコードと同じです.最も簡単な方法は、構造体またはクラスの名前を書き、後に()を付けることです.これによりdefault値を使用して構造体、クラスインスタンスが生成されます.

    Accessing Properties


    プロペティに近づくために.使用します.インスタンスの名前の後にあります.propertyの名前を付ければ、propertyに近づくことができます.
    print("The width of someResolution is \(someResolution.width)")
    // Prints "The width of someResolution is 0"
    先ほど発表したsomeVideoModeクラスの解析プログラムは構造体です.
    このとき、resolution propertyのpropertyに近づくために.もう一回撮ればいいのに
    print("The width of someVideoMode is \(someVideoMode.resolution.width)")
    // Prints "The width of someVideoMode is 0"
    変数propertyは、値を変更することもできます.
    someVideoMode.resolution.width = 1280
    print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
    // Prints "The width of someVideoMode is now 1280"

    Memberwise Initializers for Structure Types


    各構造体には、新しい構造体インスタンスのPropertiesを初期化するための自動生成されたMemberwise initializerが存在する.
    新しいインスタンスの初期化値はpropertyの名前で初期化できます.
    let vga = Resolution(width: 640, height: 480)
    構造体とは異なり、クラスインスタンスにはdefault memberwise initializerはありません.そのため、ジェネレータで直接初期化する必要があります.

    Structures and Enumerations Are Value Types


    Valueタイプ、すなわち値タイプは、変数、定数、または関数に割り当てられたときに値がコピーされることを意味します.
    この記事で先に紹介したInt、Double、Float、Bool、String、Array、Dictionaryはいずれも価値のあるタイプです.
    SWIFTのすべての構造体と列挙型は値タイプである.これは、すべての構造体、列挙インスタンスが値タイプであり、propertyが常にコピーされ、渡されることを意味します.
    Array、Dictionary、Stringなどの標準ライブラリによって定義される集合タイプは、最適化によってレプリケーションコストを削減します.
    これらのセットは、すぐにクラスをコピーするのではなく、クラスインスタンスとコピーの間に格納されているメモリを共有します.コピー、すなわちコレクションの値を変更する場合は、変更前にソースをコピーします.したがって、コードではインスタントコピーのように見えます.
    値のタイプを理解する例を見てみましょう
    let hd = Resolution(width: 1920, height: 1080)
    var cinema = hd
    cinema.width = 2048
    print("cinema is now \(cinema.width) pixels wide")
    // Prints "cinema is now 2048 pixels wide"
    print("hd is still \(hd.width) pixels wide")
    // Prints "hd is still 1920 pixels wide"
    hdは、上記のResolution構造体の例で宣言される.変数映画を宣言してhdインスタンスを割り当てます.そして映画館のwidth propertyを修正します.どんな変化がありますか?
    構造体は値タイプであるため、hdインスタンスを映画館に割り当てるとコピーされます.従って、映画館とhdは異なる例である.したがって,映画の番組値の修正はhdに何の影響も及ぼさない.

    以上の現象を図に示す.
    同じ現象が列挙型にも現れる.
    enum CompassPoint {
        case north, south, east, west
        mutating func turnNorth() {
            self = .north
        }
    }
    var currentDirection = CompassPoint.west
    let rememberedDirection = currentDirection
    currentDirection.turnNorth()
    
    print("The current direction is \(currentDirection)")
    print("The remembered direction is \(rememberedDirection)")
    // Prints "The current direction is north"
    // Prints "The remembered direction is west"

    Classes Are Reference Types


    構造体とは異なり、クラスは参照タイプです.参照タイプとは、変数または定数に割り当てられたときにコピーされず、メモリの同じ部分を一緒に表示することです.
    let tenEighty = VideoMode()
    tenEighty.resolution = hd
    tenEighty.interlaced = true
    tenEighty.name = "1080i"
    tenEighty.frameRate = 25.0
    
    let alsoTenEighty = tenEighty
    alsoTenEighty.frameRate = 30.0
    
    print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
    // Prints "The frameRate property of tenEighty is now 30.0"
    上記のコードから、VideoModeクラスのインスタンスとしてTeneightが宣言されています.
    このように宣言された[スカイライト](Skylight)を[一定](Constant)に割り当て、[スカイライト](Skylight)の構成を変更した場合、どのようなことが起こりますか?
    もちろんalsoTenEightのproperty値も修正されますがtenEightの値も修正されます.

    上の結果は図で表されています.2つのクラスインスタンスは同じメモリのみを参照するため、いずれかを変更しても2つのインスタンスに影響します.

    Identity Operators


    クラスは参照タイプであるため、複数の定数または変数は同じクラスインスタンスを参照できます.
    これが役に立つ場合があります.SWIFTには、2つの変数または定数が同じ暗黙的なインスタンスを参照するかどうかを決定する演算子があります.=====演算子が同じかどうかをチェックします!=演算子があります.
    if tenEighty === alsoTenEighty {
        print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
    }
    // Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."
    =====に等しくない.===は、同じクラスのインスタンスを参照することを決定する演算子であるため、==とは異なります.

    Pointers


    C、C++およびObjective-Cに示すように、これらの参照はポインタを使用します.
    いくつかの参照タイプインスタンスを持つ定数、変数はCのポインタと似ていますが、メモリの直接ポインタではないので、*を書く必要はありません.標準ライブラリには、ポインタタイプを直接使用する必要があるポインタとバッファタイプがあります.
    ソース:https://icksw.tistory.com/11?category=876233