DAY 10. Struct

여러 개의 작은 유형으로 하나의 유형을 만들 수 있음.

struct Album {
    let title: String
    let artist: String
    let year: Int

    func printSummary() {
        print("\(title) (\(year)) by \(artist))
    }
}

구조체를 정의한 후 값을 할당하는 등의 작업을 할 수 있음.

let endTheory = Album(title: "End Theory", artist: "Younha", year:2021)
let invu = Album(title: "INVU", artist: "TaeYeon", year: 2022)

print(endTheory.title)
print(invu.artist)

print(endTheory.printSummary())
print(invu.printSummary())

>>>
End Theory
TaeYeon
End Theory (2021) by Younha
INVU (2022) by TaeYeon

구조체가 let으로 선언된 경우 mutating 함수를 호출할 수 없다.

구조체 용어

프로퍼티: 구조체의 변수와 상수
메서드: 구조체의 함수
인스턴스: 구조체로부터 변수나 상수를 만든 경우
구조체 인스턴스 생성 시 초기화
ex) Album(title: “INVU”, artist: “TaeYeon”, year: 2022)
내부에서는 init()이라는 초기화 함수를 생성하고 전달된 인수들을 사용한다.

//인스턴스를 생성하는 두 가지 방법
var lee = Employee(name:"Lee Chan Hee", vacationRemaining: 10)
var park = Employee.init(name: "Park Chan Ho", vacationRemaining: 3)

Double도 구조체로 구현이 되어 있어, Int 값을 double로 변환하는 것이 가능해진다.

구조체에 기본값을 할당하는 것도 가능하다. 구조체 인스턴스 생성 시 기본값이 아닌 다른 값을 넣게 되면, 기본값은 사라지고 그 대신 새로운 값이 입력된다.

계산된 프로퍼티, 저장된 프로퍼티

struct Employee {
    let name: String
    var vacationRemaining: Int
}

var archer = Employee(name: "Sterling Archer", vacationRemaining: 14)
archer.vacationRemaining -= 5
print(archer.vacationRemaining)
archer.vacationRemaining -= 3
print(archer.vacationRemaining)

저장된 프로퍼티를 수정할 수 있지만, 이 경우 기존의 값이 수정되는 것이기 때문애 초기의 값을 잃어버릴 수 있다.

struct Employee {
    let name: String
    var vacationAllocated = 14
    var vacationTaken = 0

    //계산된 프로퍼티
    var vacationRemaining: Int {
        vacationAllocated - vacationTaken
    }
}

값이 변경되는 경우 저장 프로퍼티를, 프로퍼티를 자주 읽지 않는 경우 계산 프로퍼티를 사용한다.

프로퍼티 옵저버

프로퍼티 옵저버는 프로퍼티의 값이 변경되는 경우 실행된다. 프로퍼티 관찰자를 정의하기 위해 didSet, willSet 키워드를 사용한다. 각각 값이 설정된 이후, 설정되기 이전에 호출된다.

didSet 내에서 이전 값을 사용하기 위해 oldValue 키워드를 사용할 수 있다.
willSet 내에서는 newValue 키워드를 사용하여 새로운 값을 사용할 수 있다.

프로퍼티 옵저버는 값이 변경될 때 실행되기 때문에, 값이 변경될 때마다 실행할 함수들이 있는 경우 유용하게 사용된다. 주로 UI의 상태가 변경될 때 사용된다.

초기화 구문

모든 프로퍼티는 초기화 구문이 끝나면 값을 가지고 있어야 한다.

구조체 인스턴스 생성 시, 내부에서는 조용히 init()이 실행되는 것을 알 수 있었음.

멤버별(memberwise) 초기화 구문: init()을 작성하지 않으면 자동적으로 생성되는 초기화 구문.
모든 프로퍼티에 값을 넣을 수 있도록 함.
기본값을 가지는 프로퍼티는 생략할 수 있음.

init()을 직접 작성하는 것도 가능하다. 단 매개변수와 프로퍼티의 이름을 구분하는 것이 필요하다.

struct Player {
    let name: String
    let number: Int
    
    init(name:String, number:Int) {
        self.name = name
        self.number = number
    }
}

func 키워드를 사용하지 않고 정의할 수 있으며,
초기화 구문 내에서 프로퍼티를 사용할 때는 self 키워드를 프로퍼티 앞에 붙여 사용한다.

모든 프로퍼티를 생성 시 입력으로 받을 필요 없다. 함수를 통해 랜덤값을 할당하는 방법도 가능.
중요한 것은 초기화 구문이 끝나면 모든 프로퍼티가 값을 가지고 있어야 한다는 것.

사용자화 초기화 구문을 작성한 경우, 멤버별 초기화 구문에는 더 이상 접근할 수 없다.

만약 두 초기화 구문에 모두 접근하고 싶다면, 확장에 초기화 구문을 작성한다. (Day13)

카테고리:

업데이트: