21. 10. 19ストレージ構成、演算構成、init、ネストタイプ


Properties프로퍼티 値は、特定のクラス(クラス)、構造体(構造)、および列挙(enum)に関連付けられます.
  • SWIFTのプロパティ
  • ストレージ属性
  • 計算属性
  • タイプ属性
  • Stored Propertyストレージ構成
  • ストアド・プロシージャは、定数および変数の値をインスタンスの一部として格納します.
  • クラスと構造でのみ使用!
  • 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 = FixedLengthRange의 인스턴스
    구조체는 기본적으로 저장프로퍼티들을 파라미터로 가지는 이니셜라이저가 있다.
    초기값을 주면 FixedLengthRange()로 선언해도 됨. */
    
    rangeOfThreeItems.firstValue = 6
    // the range now represents integer values 6, 7, and 8
    
    /* firstValue는 변수 저장 프로퍼티로 선언되어서 값을 변경할 수 있지만,
    length는 상수 저장 프로퍼티로 선언되어 값을 변경할 수 없다. */
    
    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
    
    /* 구조체는 값 타입이기 때문에, 구조체의 인스턴스가 var로 선언되면 해당하는 구조체의
    변수 저장 프로퍼티들을 변경할 수 있지만, let으로 선언된다면 해당 구조체의 모든 프로퍼티가
    let으로 선언된 것과 같은 의미다. */
  • 参照タイプのクラスについて?
  • class FixedLengthRange {
        var firstValue: Int
        let length: Int
    
        init(firstValue : Int, length:Int) {      // 저장 프로퍼티에 초기값이 없으면,
            self.firstValue = firstValue          // 클래스에서는 반드시 init이 필요하다.
            self.length = length
        }
    }
    
    var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
    rangeOfThreeItems.firstValue = 3
    rangeOfThreeItems.length = 10       // error
    // 이건 클래스에서도 안됨.
    
    let rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
    rangeOfThreeItems.firstValue = 3
    rangeOfThreeItems.length = 10       // error
    
    /* rangeOfThreeItems를 let으로 선언했을 때, 클래스에서는 var로 선언되었던 firstValue의
    값을 변경할 수 있다. 클래스는 참조 타입이기 때문에, FixedLengthRange에 바로 접근한다.
    FixedLengthRange에서 firstValue는 var로 선언되었기 때문에 새로운 인스턴스가 let으로
    생성되었다 할지라도, 값을 변경할 수 있지만 length는 원래도 let으로 선언되어서 변경할 수 없다. */
  • Lazy Stored Properties

  • 値を使用する前に、値を計算しないプログラム.
  • lazyキーワード宣言を使用します.インスタンスの初期値が取得されない可能性があるため、初期値は常に変数として宣言する必要があります.letとして宣言されたプロセスは、初期化と同時に値を持つ必要があるため、lazyとして宣言できません.Lazy Stored Propertyは値が必要なときに初期化します!

  • 初期値がインスタンスが初期化されるまで値を知らない外部要素に依存している場合や、初期値が複雑で計算コストが高い設定が必要な場合に便利です.

  • Lazy Stored Propertyを使用すると、パフォーマンスが向上し、スペースの浪費が軽減されます.
    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
    }
    
    /* importer는 DataImporter의 인스턴스이다. */
    
    let manager = DataManager()
    // DataManager의 저장프로퍼티들은 초기값이 있어서 init이 필요하지 않음.
    
    manager.data.append("Some data")
    manager.data.append("Some more data")
    // the DataImporter instance for the importer property hasn't yet been created
    /* DataImporter의 인스턴스인 importer 프로퍼티는 lazy 저장 프로퍼티라서 
    아직 생성되지 않았음. */
    
    print(manager.importer.filename)
    /* importer 프로퍼티에 처음 액세스 할 때 만들어진다. DataManager인스턴스인 manager는 
    파일에서 데이터를 가져오지 않고도 데이터를 관리할 수 있다. DataManager 인스턴스인 manager를 
    만들 때 DataImporter 인스턴스를 만들 필요가 없음. 대신 DataImporter 인스턴스를 처음
    사용할 때 생성하는 것이 더 합리적이다. */
  • えんざんプログラム
  • 演算プログラムは、別の記憶プログラムの値を読み出し、特定の演算によって値を返す.(値は保存されません)したがって、常に変数varとして宣言する必要があります.
  • クラス、構造体、および列挙型.このタイプには、値を格納するストレージプログラムが必要です.演算プログラムは自分で値を返したり指定したりできないからです!
  • 読み取り専用であってもよいが、書くことはできない.
  • 読取り専用実施の場合はgetブロックを記入するだけでよいが、省略してもよい.
  • 読み書きが可能な場合、getおよびsetはいずれも実現しなければならない.
  • set暗黙的なパラメータnewValueを提供します.
  • 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, set이 있는걸 보아 center는 연산 프로퍼티이다.
            get {       // get에서도 변수 선언 및 값 할당이 가능하다. 리턴만 제대로 하기!
                let centerX = origin.x + (size.width / 2)
                let centerY = origin.y + (size.height / 2)
                return Point(x: centerX, y: centerY)// 리턴 타입은 center 타입과 같아야 함.
            }
            set(newCenter) {
                origin.x = newCenter.x - (size.width / 2)
                origin.y = newCenter.y - (size.height / 2)
            }  // newCenter 대신에 newValue로 넣어줘도 된다.
        }
    }
    var square = Rect(origin: Point(x: 0.0, y: 0.0),
                      size: Size(width: 10.0, height: 10.0))
    let initialSquareCenter = square.center
    
    /* center라는 프로퍼티가 (5, 5)라는 값을 가지고 있는 게 아닌,
    구조체 Point의 x와 y가 5라는 값을 가지고 있는 것이다. */
    
    square.center = Point(x: 15.0, y: 15.0)
    // 이 코드가 실행되는 순간 center의 set이 호출된다. 
    
    print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
    // Prints "square.origin is now at (10.0, 10.0)"
    タイプ属性タイプ構成
  • propertyはタイプ自体に接続されています.
  • 後ほど勉強します…
  • Initialization
  • クラスおよび構造は、タイプのインスタンスが作成されるまで、すべてのストレージ・プロシージャを適切な初期値に設定する必要があります.ストレージ・アイテムが不確定な状態にあることはできません.
  • ストアド・プロシージャの初期値を頭文字Riserに設定するか、ストアド・プロシージャを宣言するときにデフォルト値を指定する必要があります.これにより、property observerを呼び出さずにpropertyの値が直接設定されます.
  • Default Property Values
  • Propertyが常に同じ初期値を使用している場合、最初の文字Riserで初期値を設定するよりもデフォルト値を指定したほうが良いです.
  • 結果は同じですが、デフォルトではpropertyの初期化は宣言と密接に関連しています.
  • propertyのデフォルト値は、より簡潔な頭文字Liserを作成し、デフォルト値によってpropertyのタイプを推定します.
  • また、デフォルト値を使用すると、デフォルトの頭文字と頭文字の継承が容易になります
  • Customizing Initialization
  • Initialization Parameters

  • 初期化パラメータを定義する場合、ユーザーが指定した値のタイプと名前を定義できます.関数やメソッドのパラメータと同じ機能と構文を持ちます.

  • 初期化時に使用するパラメータ名と呼び出し時に使用するパラメータラベルを持つことができます.

  • イニシャルタイプライターのパラメータの前に関数のような名前はないため、イニシャルタイプライターのパラメータの名前とタイプは呼び出しが必要なイニシャルタイプライターを区別するのに重要な役割を果たす.従って、SWIFTは、初期化を提供しない場合、初期化された全てのパラメータに自動パラメータラベルを提供する.
    struct Color {
        let red, green, blue: Double
        init(red: Double, green: Double, blue: Double) {
            self.red   = red
            self.green = green
            self.blue  = blue
        }
        init(white: Double) {
            red   = white
            green = white
            blue  = white
        }
    }
    // 구조체는 하나인데 이니셜라이저는 두개다.
    
    let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
    let halfGray = Color(white: 0.5)
    // 각각 이렇게 사용할 수 있음.
    
    let veryGreen = Color(0.0, 1.0, 0.0)  // error
    // 인수 레이블이 지정되면 호출할 때 꼭 사용해야한다. 생략하면 컴파일 타임 에러~

  • 初期化パラメータでパラメータラベルを使用しない場合は、ワイルドカード()を使用してデフォルトのアクションを再定義できます.
  • Optional Property Types

  • ユーザー定義のタイプが論理的に値なしを許可するストレージ構成を持っている場合(初期化中に値を設定できないか、後で値なしになる可能性があります)、この構成は傍観者によって宣言されます.

  • 守望者タイプのpropertyは、nilの値に自動的に初期化されます.これは、初期化中にpropertyが意図的に「まだ値がない」ことを意味します.
    class SurveyQuestion {
        var text: String
        var response: String?  // 설문조사 응답은 질문 받을 때까지 알 수 없으므로 옵셔널!
        init(text: String) {
            self.text = text
        }
        func ask() {
            print(text)
        }
    }
    let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
    // 새 인스턴스가 초기화 될 때 nil 값이 자동으로 할당 된다.
    
    cheeseQuestion.ask()
    // Prints "Do you like cheese?"
    cheeseQuestion.response = "Yes, I do like cheese."
  • Assigning Constant Properties During Initialization
  • 初期化が完了する前の値に設定されている場合は、初期化中の任意の時点で定数プロセスに値を割り当てることができます.定数に値を指定した場合は、変更できません.
  • クラスインスタンスの場合、定数構成を変更できるのは、初期化中に構成を受信したクラスのみです.サブクラスは変更できません.
  • Default Initializers
  • SWIFTは、すべてのpropertyにデフォルト値を提供し、1つ以上の初期化自体を提供しないすべての構造またはクラスにdefault initializerを提供する.
  • default initializerでは、すべてのプロパティがデフォルトに設定された新しいインスタンスが作成されます.
  • class ShoppingListItem {
        var name: String?
        var quantity = 1
        var purchased = false
    }
    var item = ShoppingListItem()
    
    /* ShoppingListItem 클래스의 모든 프로퍼티에 기본값이 설정되어 있고, 상위 클래스가 없는
    기본 클래스이기 때문에 모든 프로퍼티가 기본값으로 설정된 새 인스턴스를 생성하는 기본 이니셜라이저를
    자동으로 얻는다. name의 타입이 옵셔널 String이기때문에 이 값이 코드에 작성되지 않아도 기본값으로
    nil을 할당 받는다. */
  • Memberwise Initializers for Structure Types

  • 構造体がカスタムイニシャルログインを自分で定義しない場合、memberwise initializerが自動的に受信されます.

  • デフォルトの頭文字Riserとは異なり、構造体にはデフォルト値のないストレージpropertyがあってもmemberwise initializerが受信されます.
  • memberwise initializerは、新しい構造体インスタンスのメンバープロパティを初期化する簡単な方法である.新しいインスタンスのpropertyの初期値はmemberwise initializerと命名されます.
    struct Size {
        var width = 0.0, height = 0.0     // 기본 값을 갖음.
    }
    let twoByTwo = Size(width: 2.0, height: 2.0)
    
    /* Size라는 구조체는 새 인스턴스를 초기화하는데 사용할 수 있는 멤버와이즈 이니셜라이저인 
    init(width:height:)를 자동으로 받는다. memberwise initializer를 호출할 때 
    기본값이 있는 모든 프로퍼티의 값을 생략할 수 있다. */
    
    let zeroByTwo = Size(height: 2.0)
    print(zeroByTwo.width, zeroByTwo.height)
    // Prints "0.0 2.0"
    
    let zeroByZero = Size()
    print(zeroByZero.width, zeroByZero.height)
    // Prints "0.0 0.0"
    
    // 프로퍼티 중 하나 또는 전부를 생략할 수 있고, 초기화는 생략한 모든 항목에 기본값을 사용한다.
  • Nested Types
  • 列挙型は、通常、特定のクラスまたは構造体の機能をサポートするために作成される.
  • SWIFTは、ネストされたタイプとしてサポートされる列挙タイプ、クラス、および構造体をサポートタイプの定義で定義することができる.
  • 必要に応じて重ね合わせることができる.
  • struct BlackjackCard {
    
        // nested Suit enumeration
        enum Suit: Character {
            case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
        }    // case의 rawValue가 Charater이므로, 반드시 raw type을 지정해줘야한다.
    
        // nested Rank enumeration
        enum Rank: Int {
            case two = 2, three, four, five, six, seven, eight, nine, ten
            case jack, queen, king, ace
            struct Values {
                let first: Int, second: Int?   // ace만 두 개의 값을 갖고있나 보당..
            }
            var values: Values {   // 구조체 타입의 연산프로퍼티 (열거형에선 저장프로퍼티X)
                switch self {   // self = Rank
                case .ace:
                    return Values(first: 1, second: 11)  // Value 타입의 인스턴스 반환
                case .jack, .queen, .king:
                    return Values(first: 10, second: nil)
                default:
                    return Values(first: self.rawValue, second: nil)
                }
            }
        }
    
        // BlackjackCard properties and methods
        let rank: Rank, suit: Suit    // 구조체 BlackjackCard의 저장 프로퍼티
        var description: String {     // 구조체 BlackjackCard의 연산 프로퍼티
            var output = "suit is \(suit.rawValue),"  // 지역변수 (description안에서만)
            output += " value is \(rank.values.first)"
    
    /* outout은 String이니까 여기서 +는 문자열 연결해주는 의미인듯.
    rank는 Rank 타입인데, 그안에 구조체 Values가 있고, 그 구조체 타입의 연산 프로퍼티가 values.
    이 구조체와 연산프로퍼티는 Rank라는 열거형 안에서 정의된 것이니까 rank라는 Rank타입 인스턴스에서
    접근이 가능하다! 
    지금까지의 output은 "suit is \(suit.rawValue), value is \(rank.values.first)" */
    
            if let second = rank.values.second {
                output += " or \(second)"
            }
            return output
        } 
    /* 만약 카드가 ace라면 옵셔널 바인딩으로 values에 second가 있는지 검사해서 output에 넣어줌.
    여기까지 output은 
    "suit is \(suit.rawValue), value is \(rank.values.first) or \(second)" */
    }
    
    let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades) // 인스턴스 생성
    // BlackjackCard는 구조체라서 암시적 이니셜라이저를 갖고있다.
    
    print("theAceOfSpades: \(theAceOfSpades.description)")
    // Prints "theAceOfSpades: suit is ♠, value is 1 or 11"
    /* Rank와 Suit가 BlackjackCard에 중첩되어있지만, 타입을 컨텍스트에서 유추할 수 있어서 
    인스턴스를 초기화하면, case 이름만으로 열거 case를 참조할 수 있게 된다. */
    
  • Referring to Nested Types

  • 定義したコンテキスト以外でネストタイプを使用するには、名前の前にネストタイプの名前を付けるだけです.
    let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
    // heartsSymbol is "♡"
    
    /* BlackjackCard라는 인스턴스를 만들지 않고 해당 값에 접근하려면,
    중첩 타입의 이름을 붙여서 접근하면 된다. */
  • 参考資料
    Properties - The Swift Programming Language (Swift 5.5)
    保証する
    SWIFT)属性-記憶属性
    SWIFT)属性-計算属性
    Swift ) Properties - Type Properties
    Initialization - The Swift Programming Language (Swift 5.5)
    Nested Types - The Swift Programming Language (Swift 5.5)
    Swift ) Nested Types