본문 바로가기
⌨️ Language/swift

[Swift] 프로퍼티

by hyebin (Helia) 2024. 3. 20.
저장 프로퍼티 계산 프로퍼티
값을 저장하고 있는 프로퍼티 값을 저장하고 있지 않고 특정하게 계산한 값을 반환해 주는 프로퍼티
클래스와 구조체에서만 사용 가능 클래스, 구조체, 열거형 모두에서 사용가능

저장 프로퍼티

let키워드를 이용해서 상수 혹은 var키워드를 이용해서 변수로 선언해 사용

struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}

var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 범위 값은 0, 1, 2 입니다.

rangeOfThreeItems.firstValue = 6
// 범위 값은 6, 7, 8 입니다.

 

상수 구조체 인스턴스의 저장 프로퍼티

구조체를 상수(let)로 선언하면 그 구조체 인스턴스의 프로퍼티를 변경할 수 없음

클래스는 let으로 선언하더라도 프로퍼티가 변경 가능

  • 클래스 인스턴스는 참조 타입이기 때문
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 범위 값은 0, 1, 2, 3 입니다.

rangeOfFourItems.firstValue = 6
// 에러 발생!

지연 저장 프로퍼티

  • 값이 처음으로 사용 되기 전에는 계산되지 않는 프로퍼티
  • 프로퍼티의 선언 앞에 lazy 키워드를 붙임
  • 반드시 변수(var)로 선언해야 함
    • 상수는 초기화가 되기전에 항상 값을 같는 프로퍼티인데, 지연 프로퍼티는 처음 사용되기 전에는 값을 갖지 않는 프로퍼티이기 때문

지연 저장 프로퍼티의 사용

  • 프로퍼티가 특정 요소에 의존적이어서 그 요소가 끝나기 전에 적절한 값을 알지 못하는 경우
  • 복잡한 계산이나 부하가 많이 걸리는 작업을 할 때 사용하면 실제 사용되기 전에는 실행되지 않아서 인스턴스의 초기화 시점에 복잡한 계산을 피할 수 있음

단일 스레드에서 사용할 때

  • 초기화는 한 번만 수행됨
  • 단일 스레드 환경에서는 처음으로 지연 프로퍼티에 접근하는 시점에 초기화가 수행되고, 이후에는 이미 초기화된 값이 반환됨

여러 스레드에서 접근할 경우

  • 여러 스레드가 동시에 해당 지연 프로퍼티를 평가하여 초기화를 시도 가능 => 여러 번의 초기화가 발생할 수 있음
  • 다중 스레드 환경에서 사용할 때는 동시 접근에 대한 동기화(Synchronization)를 고려해야 함

 

계산 프로퍼티

클래스, 구조체, 열거형에서 실제 값을 저장하고 있는 것이 아니라 getter와 optional한 setter를 제공해 값을 탐색하고 간접적으로 다른 프로퍼티 값을 설정할 수 있음

 

Setter 선언의 간략한 표현

struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
                let centerX = origin.x + (size.width / 2)
                let centerY = origin.y + (size.height / 2)
                return Point(x: centerX, y: centerY)
        }
        set {
                origin.x = newValue.x - (size.width / 2)
                origin.y = newValue.y - (size.height / 2)
        }
    }
}

읽기전용 계산 프로퍼티

getter만 있고 setter를 제공하지 않는 계산 프로퍼티

읽기전용 계산 프로퍼티는 반드시 반환 값을 제공하고 다른 값을 지정할 수는 없는 프로퍼티

주의!
계산된 프로퍼티를 선언시에는 반드시 let 이 아니라 var 로 선언해야함
보통 읽기전용(read-only)이라 함은 한번 값이 정해지면 변하지 않기 때문에 let 으로 선언하는 것이 맞으나 계산된 프로퍼티는 읽기전용(read-only)이라 하더라도 계산 값(width, height, depth 등)에 따라 값이 변할 수 있기 때문에 var 로 선언함

 

프로퍼티 옵저버

  • 프로퍼티에는 새 값이 설정(set) 될 때마다 이 이벤트를 감지할 수 있는 옵저버를 제공 ,새 값이 이전 값과 같더라도 항상 호출됨
  • 프로퍼티 옵저버는 지연 저장 프로퍼티에서는 사용할 수 없음
  • 계산된 프로퍼티는 setter에서 값의 변화를 감지 할 수 있기 때문에 따로 옵저버를 정의할 필요가 없음

willSet

  • 값이 저장되기 바로 직전에 호출
  • willSet에서는 새 값의 파라미터명을 지정할 수 있는데, 지정하지 않으면 기본 값으로 newValue를 사용

didSet

  • 새 값이 저장되고 난 직후에 호출
  • didSet에서는 바뀌기 전의 값의 파라미터명을 지정할 수 있는데, 지정하지 않으면 기본 값으로 oldValue를 사용
class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {
         print("About to set totalSteps to \\(newTotalSteps)")
        }
        
        didSet {
            if totalSteps > oldValue  {
                print("Added \\(totalSteps - oldValue) steps")
            }
        }
    }
}

let stepCounter = StepCounter()

stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps

stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps

stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps

 

  • willSet → 새로운 값의 파라미터명으로 newTotalSteps를 지정해서 사용
  • didSet → 변하기 전의 값을 의미하는 파라미터명을 지정하지 않고 oldValue라는 기본 파라미터명을 이용

 

전역변수와 지역변수

프로퍼티와 프로퍼티 옵저버 기능은 전역변수와 지역변수 모두에서 이용 가능

 

전역 변수

  • 함수, 메소드, 클로저 혹은 타입 컨텍스트 밖에 정의된 변수
  • 전역 상수와 변수는 lazy키워드를 붙일 필요 없이 지연 저장 프로퍼티처럼 지연 계산됨

지역 변수

  • 함수, 메소드, 클로저 혹은 타입 컨텍스트 안에 선언된 변수
  • 지역 상수와 변수는 지연 계산될 수 없음

 

타입 프로퍼티

  • 타입 프로퍼티는 특정 타입에 속한 프로퍼티로 그 타입에 해당하는 단 하나의 프로퍼티만 생성
  • 특정 타입의 모든 인스턴스에 공통으로 사용되는 값을 정의할때 유용함
주의!
타입 프로퍼티는 항상 초기값을 지정해서 사용해야함 → 타입 자체에는 초기자(Initializer)가 없어 초기화 할 곳이 없기 때문

타입 프로퍼티 구문

static 키워드를 사용

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
            return 1
    }
}

enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
            return 6
    }
}

class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
            return 27
    }
    class var overrideableComputedTypeProperty: Int {
            return 107
    }
}

타입 프로퍼티의 접근과 설정

점 문법을 사용하여 프로퍼티의 값을 가져오고 할당

print(SomeStructure.storedTypeProperty)
// Prints "Some value."

SomeStructure.storedTypeProperty = "Another value."

print(SomeStructure.storedTypeProperty)
// Prints "Another value."

print(SomeEnumeration.computedTypeProperty)
// Prints "6"

print(SomeClass.computedTypeProperty)
// Prints "27"

 

타입 프로퍼티 장점

  • 모든 인스턴스가 공유하는 값이기 때문에 메모리 사용을 효율적으로 관리 가능
    • 인스턴스마다 중복된 값을 저장할 필요가 없기 때문에 메모리 절약 가능
  • 모든 인스턴스가 동일한 타입 프로퍼티 값을 사용하기 때문에, 예상치 못한 값의 차이나 불일치 방지 가능
반응형

'⌨️ Language > swift' 카테고리의 다른 글

[Swift] 서브스크립트  (0) 2024.03.22
[Swift] 메서드  (0) 2024.03.21
[Swift] 클래스와 구조체  (0) 2024.03.19
[Swift] 클로저  (1) 2024.03.18
[Swift] 예외 처리와 함수  (4) 2024.03.17

댓글