Swift

6. Swift 프로퍼티의 종류

Daesiker 2022. 8. 3. 15:33
반응형

6-1. 개요

Swift에서 프로퍼티는 클래스, 구조체, 열거형 등에서 선언하는 상수/변수를 말한다. 다른 언어에서는 멤버라고도 하는데 Swift에서 프로퍼티는 총 5가지가 존재한다.

  • 저장프로퍼티(Stored Properties)
  • 지연 저장 프로퍼티(Lazy Stored Properties)
  • 연산 프로퍼티(Computed Properties)
  • 프로퍼티 감시자(Properties Observers)
  • 타입 프로퍼티(Type Properties)

6-2. 저장 프로퍼티(Stored Properties)

저장 프로퍼티는 가장 기본적인 프로퍼티로 클래스 또는 구조체의 인스턴스와 연관된 값을 저장하는 프로퍼티이다. let이나 var 키워드를 통해 상수나 변수로 선언할 수 있다. 옵셔널 타입이 아니라면 기본값이 있거나 사용자 정의 init을 할 때 초기화를 해주어야 한다.

import Foundation

class Human {
    //저장 프로퍼티
    var name:String
    var age:Int

    init(_ name: String, _ age: Int) {
        //옵셔널이 아닌 저장프로퍼티 2개는 반드시 초기화를 해주어야한다.
        self.name = name
        self.age = age
    }
}

let human = Human("daesiker", 26)
print(human)

6-3. 지연 저장 프로퍼티(Lazy Stored Properties)

지연 저장 프로퍼티는 해당 프로퍼티가 호출되기 전까지는 선언말 될 뿐 초기화되지 않고 있다가, 프로퍼티가 호출한 순간에 초기화되는 저장 프로퍼티이다. 항상 변수로 선언되어야 한다.

import Foundation

class Human {
    //저장 프로퍼티
    var name:String
    var age:Int

    init(_ name: String, _ age: Int) {
        //옵셔널이 아닌 저장프로퍼티 2개는 반드시 초기화를 해주어야한다.
        self.name = name
        self.age = age

        print("\\(name) init🐽")
    }
}

class House {
    var width:Int
    var height:Int
    lazy var person:Human = Human("Daesiker", 26)

    init(_ width: Int, _ height: Int) {
        self.width = width
        self.height = height
        print("House init🏠")
    } 
}

let house:House = House(20, 20)
//House init🏠
house.person.age += 1
//Daesiker init🐽

코드로 예를 들어보면 일반적인 프로퍼티였다면 맨 처음에 House Instance를 선언했을 때 선언문에 있는 print함수가 호출되면서 "House init🏠"과 "Daesiker init🐽"이 같은 시점에 호출되어야 하지만, lazy로 호출된 지연 프로퍼티는 초기화가 되지 않아서 “House init🏠”만 호출되는 것을 알 수 있다. 그리고 나중에 지연 프로퍼티를 처음으로 호출할 때 해당 프로퍼티가 초기화 된걸 알 수 있다.

지연 저장 프로퍼티가 변수로만 선언할 수 있는 이유는 let으로 선언될 경우에 해당 프로퍼티가 필요한 시점에 초기화를 진행할 수 없기 때문이다. 메모리에는 할당이 되어있지만, 필요한 시점에 사용자가 원하는 값으로 초기화가 돼야 해서 var로만 선언이 가능하다.


6-4. 연산 프로퍼티(Computed Properties)

연산 프로퍼티는 클래스, 구조체, 열거형에서 사용된다. 저장 프로퍼티와 달리 특정 상태에 따른 값을 연산하는 프로퍼티이다. 인스턴스 내/외부의 값을 연산하여 값을 돌려주는 getter의 역할과 내부의 프로퍼티 값을 간접적으로 설정하는 setter의 역할을 수행할 수 있다. getter은 읽기 능력을 수행하는 것이고 setter은 쓰기 능력을 수행하는 것이다.

class People {
    //저장 프로퍼티
    private var _name:String = ""
    //연산 프로퍼티
    var name:String {
        get {
            return self._name
        } set {
            //파라미터명을 지정하지 않으면 newValue가 바뀌는 값
            self.name = newValue
        }
    }

    private var _age:Int = 28
    var age:Int {
        get {
            return self._age
        //age가 newValue로 사용됨
        } set(age) {
            self._age = age
        }
    }

    private var _address:String = "경기도"
    var address:String {
        //get만 사용할 수는 있지만 set만 사용할 수는 없다.
        get {
            return self._address
        }
    }
    
}

연산 프로퍼티는 독자적으로는 사용할 수 없고 저장 프로퍼티와 같이 사용해야 한다. 연산 프로퍼티는 말 그대로 연산만 하는 거라서 값을 저장하는 공간이 필요하다. 그래서 보통 저장 프로퍼티에 접근 지정자를 private로 해서 접근을 막고 연산 프로퍼티만 저장프로퍼티에 접근을 할 수 있게 설정을 한다.

name 연산 프로퍼티를 보면 읽기,쓰기가 둘다 구현되어 있는데 get에서는 어떤 값을 읽을지를 return을 해주면 되고 set은 변경될 데이터를 newValue라는 default 파라미터에 저장되어 있다.

사용할 때는 저장 프로퍼티 사용시와 동일하다.

people.name = "Daesiker" //set
print(people.name) //get

set을 사용할 때 newValue말고 다른 파라미터를 사용하고 싶은경우는 age 연산 프로퍼티의 set부분과 같이 사용자가 지정하면 된다.

마지막으로 get-only 방식인데 이때는 저장 프로퍼티의 값을 바꾸지 못하고 해당 저장 프로퍼티의 값을 호출만 가능하다. 말 그대로 읽기전용인 것이다.

set-only는 사용할 수 없다.


6-5. 프로퍼티 감시자(Property Observer)

프로퍼티 감시자는 말 그대로 프로퍼티의 값이 변경되는지 감시해주는 역할을 한다. 저장 프로퍼티에서만 사용할 수 있고 프로퍼티가 변경되었을 때 동작하므로 변수에서만 적용이 가능하다.

class Account {
    var money:Int = 0 {
        willSet {
            print("잔액 변경 예정 \\(money)원 -> \\(newValue)")
        }
        didSet {
            print("잔액 변경 완료 \\(oldValue)원 -> \\(money)")
        }
    }
}

let account = Account()

account.money = 10000
//잔액 변경 예정 0원 -> 10000
//잔액 변경 완료 0원 -> 10000
  • willSet : 저장 프로퍼티의 값이 바뀌기 직전에 호출되는 감시자로 바뀌기 전의 값은 저장 프로퍼티의 이름으로 호출이 가능하고 바뀔 값은 newValue라는 파라미터로 사용이 가능하다.
  • didSet : 저장 프로퍼티의 값이 바뀐 직후에 호출되는 감시자로 바뀌지 전의 값은 oldValue라는 파라미터로 사용할 수 있고 바귄 값은 저장프로퍼티의 이름으로 사용 가능하다.

6-6. 타입 프로퍼티(Type Properties)

타입 프로퍼티는 클래스, 구조체, 열거형에서 사용되는 프로퍼티로 저장 타입 프로퍼티와 연산 타입 프로퍼티에서만 사용이 가능하며, 항상 값이 초기화되어 있어야한다. static이란 키워드를 통해 선언을 하며, 지연 저장 프로퍼티랑 같은 형식으로 동작한다. 타입 프로퍼티는 메모리 중 데이터 영역에 저장되어 프로그램 시작과 동시에 메로리 할당이 되고 프로그램이 종료되면 해제가 된다.

class Account {

    static var account:Int = 1000

    var money:Int = 0 {
        willSet {
            print("잔액 변경 예정 \\(money)원 -> \\(newValue)")
        }
        didSet {
            print("잔액 변경 완료 \\(oldValue)원 -> \\(money)")
        }
    }
}

Account.account = 2000
print(Account.account)
//2000

타입 프로퍼티는 해당 타입 프로퍼티가 선언된 타입 자체에서 호출이 가능하다. 따라서 인스턴스의 개수와 상관없이 해당 타입에 선언된 타입 프로퍼티는 단 1개이다. 주로 싱글톤 방식에서 많이 사용한다.

참조
https://babbab2.tistory.com/118
https://jinshine.github.io/2018/05/22/Swift/6.%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0(Property)/
반응형