Weekoding

[Swift] Property(프로퍼티) 본문

공부 노트(Swift)

[Swift] Property(프로퍼티)

Weekoding 2022. 10. 3. 12:16

Swift 공부 중 Property Observer라는 재밌는 걸 알아냈다.

근데 애초에 Property 값에 대한 Oberver라는 의미이므로,

Property에 대해 기본적으로 이해하고 있어야 해서

멀리 돌고 돌아 공부해 보기로 했다.

 

 

Property

- 사전적 의미: '속성'

- 공식 문서를 살펴보면, Swift에서는 다음과 같은 의미를 갖는다.

Properties associate values with a particular class, structure, or enumeration.

특정 클래스, 구조체, 열거형과 연관된 값들을 프로퍼티라고 한다. 

 

 

문서를 읽어보면, 추가로 세 가지에 대한 개념이 더 나와있다.

오늘 우리가 다루어볼 내용들이다.

Stored properties store constant and variable values as part of an instance,
whereas computed properties calculate (rather than store) a value.

저장(Stored) 프로퍼티는 인스턴스의 일부로서 상수나 변수를 저장하는 반면, 계산(Computed) 프로퍼티는 값을 계산한다.

 Computed properties are provided by classes, structures, and enumerations.
Stored properties are provided only by classes and structures.

계산 프로퍼티는 클래스, 구조체, 열거형에서 제공되며,

     저장 프로퍼티는 클래스, 구조체에서만 제공된다.

Stored and computed properties are usually associated with instances of a particular type.
However, properties can also be associated with the type itself. Such properties are known as type properties.

저장 / 계산 프로퍼티는 주로 특정 타입의 인스턴스와 연관이 되어있다. 

    그러나, 프로퍼티들은 타입 자체와도 연관이 되어있을 수 있는데, 이를 타입(Type) 프로퍼티라고 한다.

 

 

 

📂 저장 프로퍼티(Stored Properties)

저장 프로퍼티는, 클래스와 구조체 인스턴스의 일부로 저장되는 상수 혹은 변수이다.

말이 어렵게 보일 수 있겠지만, 구조체와 클래스의 let, var 키워드로 통용되는 상수와 변수를 의미한다. 

또한, 저장 프로퍼티 정의 시 기본값을 부여할 수 있다.

 

예시 코드를 통해 더 알아 보자.

// let 키워드를 쓰는 상수 프로퍼티는 변경할 수 없다.
// struct - Value Type(call by value), 
// class - Reference Type(call by reference)이기 때문에
// 인스턴스 프로퍼티를 생성 했을 때 차이점이 존재한다.

struct PizzaStore{
  let storeOrder: Int //상수 저장 프로퍼티
  var deliveryOrder: Int //변수 저장 프로퍼티
}

//구조체형 변수 인스턴스
var seoulPizza = PizzaStore(storeOrder: 4 ,deliveryOrder: 10) 
seoulPizza.storeOrder = 7 //ERROR
seoulPizza.deliveryOrder = 15

//구조체형 상수 인스턴스
let busanPizza = PizzaStore(storeOrder: 4, deliveryOrder: 10)
busanPizza.storeOrder = 8 //ERROR
busanPizza.deliveryOrder = 19 //ERROR
//value를 가져온 것이기 때문에, let형 인스턴스면 아무것도 변경할 수 없음



class ChickenStore{
  let storeOrder: Int
  var deliveryOrder: Int
  
  init(store: Int, delivery: Int){
    self.storeOrder = store
    self.deliveryOrder = delivery
  }
}

//클래스형 변수 인스턴스
var seoulChicken = ChickenStore(store: 5, delivery: 20)
seoulChicken.storeOrder = 8 //ERROR
seoulChicken.deliveryOrder = 19

//클래스형 상수 인스턴스
let busanChicken = ChickenStore(store: 2, delivery: 12)
busanChicken.storeOrder = 8 //ERROR
busanChicken.deliveryOrder = 19
//reference를 통해 원본에 접근하기 때문에, let형 인스턴스여도 var형 프로퍼티는 접근하여 수정이 가능

 

또한, 저장 프로퍼티에는 Lazy Stored Properties(게으른 저장 프로퍼티)도 존재한다.

최초로 사용되기 전 까지는 값이 계산되지 않는 프로퍼티이며, 'lazy' 키워드를 통해 사용할 수 있다. 

이전에 포스팅 해놓은 것이 있다.

 

[Swift] lazy Variable

공부하던 중 lazy 키워드를 발견했다. Bruno Mars의 'The Lazy Song'이 먼저 생각나는 걸 보니 아직 많이 부족한가보다^^ 농담은 그만하고 바로 알아보도록 하자! 📂 ' lazy ' : 게으른, 여유로운 : "A lazy stor

weekoding.tistory.com

 

 

 

📂 계산 프로퍼티(Computed Properties)

계산 프로퍼티는 연산 프로퍼티라고도 불리며. 실제적으로값이 저장되지 않는 프로퍼티이다. 

그 대신, gettersetter를 제공하여 간접적으로 다른 프로퍼티와 값을 주고 받을 수 있다.

즉, 계산 프로퍼티는 자기 스스로를 return하거나 직접 값을 지정해 줄 수 없다.

그래서 저장 프로퍼티를 최소 하나 이용하여 값을 주고받으며 연산을 진행한다.

 

그리고 이러한 특성 때문에, 계산 프로퍼티반드시 'var'로 선언해주어야 한다. 

 

 

이 친구도 코드를 통해 더 살펴보자.

class DiscountProduct{
  var price: Int = 0
  
  var doDiscount:Int {
    get{
      return price 
      //리턴 타입은 프로퍼티의 타입과 일치해야 한다
    }
    
    set{
      price = newValue * 0.8
    }
    //set(변수명)의 형태로 선언하여 내부에서 다른 이름을 사용할 수 있지만,
    //생략했을 경우에는 무조건 'newValue' 키워드를 사용해야 한다.
  }
}

var customer: DiscountProduct = DiscountProduct()
customer.doDiscount = 30000 //price에 24000(30000 * 0.8)가 저장된다

var howMuch = customer.doDiscount //price를 return
print(howMuch) //24000

doDiscount라는 계산 프로퍼티는 값을 연산하여 할당하거나, 리턴해주는 역할을 한다는 것을 알 수 있다.

 

또한 getter는 반드시 구현해야 하지만, setter는 구현하지 않아도 된다.

getter만 있는 프로퍼티의 경우 이를 Read-Only Computed Properties 라고 한다. 

struct CubeArea{
  var edge: Int = 0
  var area: Int{
    get{	
      return edge * edge * 6
    } //get{}은 생략하고 return만 작성하는 것도 가능하다.
  }
}

var myCube: CubeArea = CubeArea()
myCube.edge = 3
print(myCube.area) //54

 

 

 

📂 타입 프로퍼티(Type Properties)

타입 프로퍼티타입 자체에 속하는 프로퍼티이다. 인스턴스에 속하지 않았다는 것이다.

다시 말해, 같은 타입이라면 그 어떤 인스턴스에서도 접근할 수 있는 값이라는 것을 의미한다.

 

예를 들어보자.

class Grade{
 let schoolName: String = "Swift Elementary School"
 var schoolYear: Int
 
 init(year: Int){
   self.schoolYear = year
 }
}

var minsu: Grade = Grade(year: 3)
var nayoung: Grade = Grade(year: 5)
//각각의 인스턴스에 schoolName, schoolYear또한 별개로 속해 있다.

그러나 여기서 타입 프로퍼티 Grade라는 '타입' 자체에 속하게 되며,  minsu나 nayoung 그 어떤 인스턴스든지 접근이 가능하다.

전역변수의 개념과 비슷하다.

 

🔍 접근 방법

타입 자체에 속하는 것이니 만큼,

minsu.typeProperty 처럼 [ 인스턴스명. ]을 통해 접근하는 것이 아닌                

Grade.typeProperty 처럼 [ 타입명. ]을 통해 바로 접근한다.

 

🔍 주의점

타입 '저장' 프로퍼티를 사용할 때에는, 선언과 동시에 초기화를 해 주어야 한다.

인스턴스가 생성될 때 마다 인스턴스 멤버로써 매번 생성되는 기존의 프로퍼티와 달리,

최초 호출이 되어 한번 메모리에 올라가면, 그 뒤로는 재생성 되지 않고 언제든 해당 타입 프로퍼티에 접근할 수 있기 때문이다.

그래서 인스턴스 생성 시 호출되는 init과는 전혀 무관하기 때문에 이후에 초기 값을 세팅할 방법이 없다.

 

⌘ lazy variable vs type properties?

여기서 겉보기에 lazy variable과 비슷해보이는 타입 프로퍼티의 다른 점이 나타난다.

 

lazy variable은 저장 프로퍼티의 일종으로, 인스턴스에 속해있기 때문

초기화 단계에서는 값이 '없음' 상태로 되어 있다가 최초로 호출될 때 초기화가 된다.

그러한 이유로, 'lazy''let'으로 설정하게 되면 한번 설정된 '없음' 상태인 값을 변경할 수 없기 때문에

선언 시 'let' 키워드를 사용할 수 없었다.

 

type properties인스턴스에 속해있는 개념이 아니기 때문에 init의 영향권 밖이다.

'없음'으로 되어있는 것도 아니고 정말 말 그대로 최초 호출시에 값이 초기화 되는 것이다.

따라서 type stored properties라면 반드시 선언과 동시에 초기값을 지정해주어야 한다.

또한 인스턴스의 init과정을 거치지 않기 때문에 선언 시 'let' 키워드도 사용이 가능하다.

 

 

🔍 선언 방법

'class''static'이 있다. 차이를 알아보자.

   static   class
Keyword  일반적으로 타입 프로퍼티를 선언할 때 쓰인다.  'class' 키워드를 계산 프로퍼티와 함께 사용하면, 
 클래스간 상속 시에 overriding이 가능하다.

 

class Ramen{
  static var meat = "Chashu"
  static let degree = 100
  class var flavor {
    return "Original Ramen" 
  }
}

class ShoyuRamen:Ramen{
  override class var flavor {
    return "Shoyu Ramen" 
  }
}

//Type에 직접 접근하여 값을 수정
Ramen.meat = "Chicken Breast"
print(Ramen.meat) //"Chicken Breast"

//overriding
print(Ramen.flavor)	//"Original Ramen"
print(ShoyuRamen.flavor) //"Shoyu Ramen"

 

 

🔍 어디서 쓸까?

타입 프로퍼티는 싱글톤 패턴에서 자주 쓰이는 프로퍼티라고 한다. 싱글톤 패턴에 대해선 다음번에,,

 

 

 

 

 

 

📌 마치며

기본적으로 많이 쓰던 저장 프로퍼티는 휙휙 넘어갈 수 있었는데,,

계산, 타입 프로퍼티는 조금 생소하여 확실히 읽히는 속도가 많이 느려졌었다.

요즘 공부할 때 마다 하나의 개념이 그물망 처럼 다른 개념들과 얼기설기 얽혀있다는 느낌이 든다.

새로운 것을 같이 묶어서 더 배우기도 하고, 이전에 공부했던 것을 다시 꺼내서 공부하기도 한다. 

정리해 두었던 lazy variables도 오랜만에 봐서 반가웠다~

 

 

 

오류 및 지적사항은 댓글로 남겨주시면 감사하겠습니다!

참고 : 

https://docs.swift.org/swift-book/LanguageGuide/Properties.html

https://zeddios.tistory.com/243

https://zeddios.tistory.com/245

Comments