이 포스팅은 Swift 시리즈 20 편 중 4 번째 글 입니다.

  • Part 1 - 01: Optional, Any, AnyObject, nil
  • Part 2 - 02: struct, class, enum
  • Part 3 - 03: Closure
  • Part 4 - This Post
  • Part 5 - 05: 상속, 생성자, 소멸자
  • Part 6 - 06: 옵셔널 체이닝과 nil 병합
  • Part 7 - 07: 타입 캐스팅
  • Part 8 - 08: assert, guard
  • Part 9 - 09: Protocol
  • Part 10 - 10: Extention
  • Part 11 - 11: 오류처리
  • Part 12 - 12: 고차함수
  • Part 13 - 13: ARC(Automatic Reference Counting)
  • Part 14 - 14: Access control, Access modifier
  • Part 15 - 15: Generics
  • Part 16 - 16: Optional에 대한 깊은 이해
  • Part 17 - 17: Lazy Variables
  • Part 18 - 18: Enumeration
  • Part 19 - 19: Initialization
  • Part 20 - 20: Concurrency
▼ 목록 보기

프로퍼티

  • 앞에서 배운 내용인데, 좀 더 명확하게 구분해보자.

프로퍼티의 종류

  • 역할에 따른 분류
    • 인스턴스 프로퍼티
    • 타입 프로퍼티
  • 종류
    • 저장 프로퍼티
    • 연산 프로퍼티
      • var로만 선언 가능
      • 읽기 전용 구현은 가능 - get 블록을 작성
      • 쓰기 전용 구현은 불가능

위의 4가지가 섞여서 존재할 수 있다. 즉 4가지의 가능성이 존재.

  • 인스턴스 저장 프로퍼티
  • 타입 저장 프로퍼티
  • 인스턴스 연산 프로퍼티
  • 타입 연산 프로퍼티

프로퍼티의 정의

  • 구조체, 클래스, 열거형 내부에 구현이 가능
  • 열거형에는 연산 프로퍼티만 구현 가능
  • 읽기 쓰기 모두가능하게 하려면 get 블럭과 set 블럭 모두 구현
    • 읽기 전용으로 만들고 싶으면 get만 구현
  • set에서 암시적 매개변수 newValue를 사용할 수 있음
struct Student {
    // 인스턴스 저장 프로퍼티
    var name: String = ""
    var `class`: String = "Swift"
    var koreanAge: Int = 0
    
    // 인스턴스 연산 프로퍼티
    var westernAge: Int {
        get {
            return koreanAge - 1
        }
        set(inputValue) {
            koreanAge = inputValue + 1
        }
    }
    
    // 타입 저장 프로퍼티
    static var typeDescription: String = "학생"
    
    // 읽기 전용 타입 연산 프로퍼티
    // 읽기 전용이 default라 적지 않으면 읽기전용이라고 판단함
    static var selfintroduction: String {
        return "학생타입입니다."
    }
}
  • 인스턴스 저장 프로퍼티는 일반적이니 패스
  • 인스턴스 연산 프로퍼티는, 특정값을 받아서 다른 저장 인스턴스의 값을 설정해줘야 한다거나 다른 프로퍼티로 부터 연산을 통해 해당 프로퍼티의 값이 도출될 때 주로 사용
  • 타입 저장 프로퍼티는 기존에 알고 있던 타입 프로퍼티
  • 타입 연산 프로퍼티 역시 비슷하다.

이러한 방법을 사용하면 기존의 introduce와 같은 함수를 읽기 프로퍼티를 사용하여 대체하는 것도 가능

// 인스턴스 생성
var wansik: Student = Student()
wansik.name = "wansik"
wansik.koreanAge = 20

// 인스턴스 저장 프로퍼티 사용
print(wansik.name) // wansik

// 인스턴스 연산 프로퍼티 사용
print(wansik.westernAge) // 19

// 타입 저장 프로퍼티 사용
print(Student.typeDescription) // 학생

// 타입 연산 프로퍼티 사용
print(Student.selfintroduction) // "학생타입입니다."

연습

struct Money {
    var currencyRate: Double = 1100
    var dollar: Double = 0
    var won: Double {
        get {
            return dollar * currencyRate
        }
        set(newValue) {
            dollar = newValue/currencyRate
        }
    }
}

var moneyInMyPocket = Money()

// 인스턴스 연산 프로퍼티에 쓰기 시도
moneyInMyPocket.won = 11000
print(moneyInMyPocket.won) // 11000
print(moneyInMyPocket.dollar) // 11

// 인스턴스 연산 프로퍼티에 읽기 시도
moneyInMyPocket.dollar = 10
print(moneyInMyPocket.won) // 11000
  • 이렇게 연산 프로퍼티는 두개 이상의 입력으로 프로퍼티를 설정할 수 있을 떄, 서로 다른 두개의 프로퍼티가 관계를 가지고 있는 경우, 한번의 할당으로 두 개 이상의 프로퍼티를 할당할 수 있다.

프로퍼티 감시자

  • 프로퍼티 감시자를 사용하면 프로퍼티 값이 변경될 때, 원하는 동작을 수행할 수 있음
  • 값이 변경되기 직전에 willSet 블럭이, 변경 직후 didSet 블럭이 호출됨
  • 변경되려는 값이 기존 값과 같더라도 항상 동작
  • willSet 블럭에서 암시적 매개변수 newValue를 사용 가능
  • didSet 블럭에서는 oldValue를 사용 가능
  • 프로퍼티 감시자는 연산 프로퍼티에서 사용 불가
  • 함수, 메서드, 클로저, 타입 등의 지역/전역 변수에 모두 사용 가능
struct Money {
    // 프로퍼티 감시자 사용
    var currencyRate: Double = 1100 {
        willSet(newRate) {
            print("환율이 \(currencyRate)에서 \(newRate)으로 변경될 예정입니다")
        }
        didSet(oldRate) {
            print("환율이 \(oldRate)에서 \(currencyRate)으로 변경되었습니다")
        }
    }
    
    // 매개 변수를 암시적으로 newValue, oldValue를 갖는다.
    var dollar: Double = 0 {
        willSet {
            print("\(dollar)달러에서 \(newValue)달러로 변경될 예정입니다")
        }
        didSet {
            print("\(oldValue)달러에서 \(dollar)달러로 변경되었습니다")
        }
    }
    
    // 연산 프로퍼티
    var won: Double {
        get {
            return dollar * currencyRate
        }
        set {
            dollar = newValue / currencyRate
        }
        // get, set과 함께 사용이 불가함
//        willSet {
//            print("원화의 값이 \(won)으로 변경될 예정입니다.")
//        }
//        didSet {
//            print("원화의 값이 \(won)으로 변경되었습니다.")
//        }
    }
}

var moneyInMyPocket = Money()

// 환율이 1100.0에서 1150.0으로 변경될 예정입니다
moneyInMyPocket.currencyRate = 1150.0
// 환율이 1100.0에서 1150.0으로 변경되었습니다

//0.0달러에서 10.0달러로 변경될 예정입니다
moneyInMyPocket.won = 11500
//0.0달러에서 10.0달러로 변경되었습니다

print(moneyInMyPocket.dollar) // 10

Reference

iOS 프로그래밍을 위한 스위프트 기초