大器晩成

타입속성 (Type Properties) 본문

iOS/Swift 문법

타입속성 (Type Properties)

zerobugpark 2024. 11. 22. 18:11

 

  • 클래스나 구조체, 또는 열거형과 같은 객체 자체에 관련된 값을 다루어야 할 때도 있는데, 이때는 인스턴스를 생성하지 않고 클래스나 구조체 자체에 값을 저장하게 되며 이를 타입 프로퍼티(Type Property)라고 부릅니다.
  • 타입 프로퍼티는 클래스나 구조체의 인스턴스에 속하는 값이 아니라 클래스나 구조체 자체에 속하는 값이므로 인스턴스를 생성하지 않고 클래스나 구조체 자체에 저장되며, 저장된 값은 모든 인스턴스가 공통으로 사용할 수 있습니다.
  • 인스턴스 프로퍼티는 개별 인스턴스마다 다른 값을 저장할 수 있어서 하나의 인스턴스에서 변경한 프로퍼티의 값은 그 인스턴스 내에서만 유지될 뿐 나머지 인스턴스에 영향을 미치지 많지만, 타입프로퍼티는 인스턴스가 아무리 많더라도 모든 인스턴스가 하나의 값을 공용으로 사용한다.
// 클래스 내부에서
 static let/var 프로퍼티명 = 초기값
 또는

class let/var 프로퍼티명: 타입 {
    get {
        return 반환값
    }
    set {
    }
}
  • 타입 프로퍼티를 정의하는 또 다른 키워드인 class는 클래스에서 연산 프로퍼티에만 붙일 수 있는 키워드입니다.
  • 구조체이거나 저장 프로퍼티일 경우에는 사용할 수 없습니다. 이 키워드를 사용하여 타입 프로퍼티를 선언하면 상속받은 하위 클래스에서 재정의 할 수 있는 타입 프로퍼티가 됩니다.
  • 변수나 상수 어느 것이든 타입 프로퍼티를 사용할 수 있지만, 이를 이용하여 정의한 저장 프로퍼티를 타입 프로퍼티로 선언할 때에는 초기값을 반드시 할당해야 합니다.
  • 타입 프로퍼티는 인스턴스와 상관없기 때문에 인스턴스 생성과정에서 초기값을 할당할 수 없습니다.
  • 인스턴스에 속한 속성이 아니고, 타입자체에 속한 속성이기에 /외부에서 Type.property로 접근해야 합니다
  • 저장 타입 속성을 주로 사용합니다.
struct Foo {
    //타입 저장 프로퍼티
    static var sFoo = "구조체 타입 프로퍼티 값"
    
    //타입 연산 프로퍼티
    static var cFoo: Int {
        return 1
    }
}
//이렇게 선언되 낱입 프로퍼티들은 별도의 인스턴스 생성 없이 사용 가능
//클래스나 구조체 자체에 점 구문을 이용하여 타입 프로퍼티 참조
print(Foo.sFoo) // 구조체 타입 프로퍼티 값
Foo.sFoo = "새로운 값"
print(Foo.sFoo) // 새로운 값

class Boo {
    //타입 저장 프로퍼티
    static var sboo = "클래스 타입 프로퍼티 값"
    
    //타입 연산 프로퍼티
    static var cBoo: Int {
        return 10
    }
    
    // 재정의 가능한 타입 연상 프로퍼티
    class var oCoo: Int {
        return 100
    }
}
print(Boo.sboo) // 클래스타입 프로퍼티 값
Boo.sboo = "새로운 값"
print(Boo.sboo) // 새로운 값

// 타입 프로퍼티는 인스턴스에 속하지 않는 값이므로 만약 인스턴스를 생성한 다음 점 구문을 이용하여 
// 타입 프로퍼티를 읽으려고 하면 선언되지 않은 프로퍼티라는 오류 발생

//let a = Foo()
//a.sFoo // => 인스턴스에서 .(점)을 찍어도 속성으로 보이지 않는다.

Boo.sboo // ==> 반드시 타입(형식)의 이름으로 접근해야 함
  • 이 값은 복사된 것이 아니라 실제로 하나의 값이므로 하나의 인스턴스에서 타입 프로퍼티의 값을 변경하면 나머지 인스턴스들이 일괄적으로 변경된 값을 적용받습니다.
  • 이런 특성 때문에 타입 프로퍼티는 특정 클래스나 구조체, 그리고 열거형에서 모든 인스턴스들이 공유해야 하는 값을 정의할 때 유용합니다.

 

저장 타입(형식) 속성

class Circle {
    //(저장) 타입 속성 (값이 항상 있어야 함)
    static let pi = 3.14
    static var count = 0 // 인스턴스를 (전체적으로) 몇개를 찍어내는지 확인
    
    //저장 속성
    var radius: Double // 반지름
    
    //계산 속성
    var diameter: Double {
        get {
            return radius * 2
        }
        set {
            radius = newValue / 2
        }
    }
    
    //생성자
    init(radius: Double) {
        self.radius = radius
        Circle.count += 1
    }
}

var circle1 = Circle(radius: 5) // 인스턴스를 +1개 찍어냈다. (count == 1)
var circle2 = Circle(radius: 10) // 인스턴스를 +1개 찍어냈다. (count == 2)

let a = Circle.pi

// 실제 사용 예시)

Int.max
Int.min

Double.pi

 

저장 타입 속성 정리

  • 클래스나 구조체 또는 열거형에서 정의할 시 static 키워드를 사용합니다.
  • 일반 저장속성은 인스턴스를 생성할 때, 생성자에서 모든 속성에 대한 초기화를 완료하지만, 저장 타입 속성은 클래스나 구조체 자체에서 값을 선언합니다.
  • 저장 타입 속성의 경우 let이나 var 둘 다 가능합니다.
  • 저장 타입(형식) 속성은 생성자가 따로 없기 때문에, 타입 자체(유형 그 자체)에 속한 속성이기 때문에 항상 기본값(초기값)이 필요하며. 생략 불가능 불가능합니다.
  • 타입 저장 속성은 기본적으로 타입 저장 속성에 접근 시 초기화되기 때문에, 지연 속성의 성격을 가집니다.
  • 저장 타입속성은 기본적으로 지연 속성 (속성에 처음 접근하는 순간에 초기화됨)이지만, lazy라고 선언할 필요는 없습니다
    (참고: 여러 스레드에서 동시에 액세스 하는 경우에도 한 번만 초기화되도록 보장됨. Thread-Safe) 

저장 타입속성을 선언하는 경우

  • 모든 인스턴스가 동일하게 가져야 하는 속성일 때
  • 모든 인스턴스가 공유해야 하는 성격에 가까울 때

 

계산 타입(형식) 속성

class Circle {
    //(저장) 타입 속성 (값이 항상 있어야 함)
    static var radius = 3.0
 
    //계산 타입 속성 (Read-Only)
    static var diameter: Double {
        return radius * 2
    }
    
}

Circle.diameter
  • 상속이 있는 경우, 계산 타입 속성에서는 static대신 class 키워드를 사용합니다.
  • static(의미: 고정적인) 또는 class 키워드 사용(static 상속 시 재정의 불가/class 상속 시 재정의 가능 의미임)
  • var 키워드만 사용 가능(계산 타입 속성) -> 계산속성도 var만 사용 가능
  • 메서드이기 때문에 타입에 메모리 공간이 할당되어 있지 않음(계산 속성)

 

인스턴스 내에서도 접근 가능

class Circle {
    
    // 저장 타입 속성
    static let pi: Double = 3.14
    
    // 저장 속성
    var radius: Double
    
    // 생성자
    init(radius: Double) {
        self.radius = radius
    }
    
    // 넓이 구하기 ==>  원의 넓이 공식 ==> 파이 X 반지금 제곱
    func getArea() -> Double {
        
                   // 타입이름으로 접근해야함
        let area = Circle.pi * radius * radius      // 내부 인스턴스에서도 타입 속성에 접근할때 주의
        return area
    }

}

let c1 = Circle(radius: 3)
c1.getArea()
  • 인스턴스 내에서도 접근하려면 타입이름 + 속성으로 써야 접근 가능합니다.
728x90