ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Swift] 프로퍼티(Property)- 프로퍼티의 정의, 종류
    iOS 2022. 8. 9. 22:05

    증말 기본적인 개념인데도 그냥 대애충 두루뭉술하게만 알고 넘어갔었더라고요 🥲

    막상 구체적으로 문제가 나오니까 확실히 아는게 없는 것 같아서 

    이번 기회에 한 번 정리해봅니다 ><

     

     

     

    목차

       

       

      Properties associate values with a particular class&#44; structure&#44; or enumeration.
      프로퍼티란, 클래스나 구조체 또는 열거형에 값을 할당합니다.

      프로퍼티란 어떤 대상(클래스,구조체,열거형etc.)에 값을 할당해주는 존재입니다.

      프로퍼티는 크게 저장 프로퍼티,  연산  프로퍼티로 나눌 수 있습니다!

       

       

      저장 프로퍼티 (Stored Properties)

      Stored Properties

      ► 이름에서 알 수 있듯 가장 단순하고 기본적인 개념의 프로퍼티로, 클래스 또는 구조체의 인스턴스와 연관된 값을 저장하는 프로퍼티

      ► 클래스 / 구조체에서만 사용 가능!! (열거형x)

       

      - 변수 저장 프로퍼티 (variable stored properties) - var 키워드 사용

      - 상수 저장 프로퍼티 (constant stored properties) - let 키워드 사용

       

      struct Point {
        var x: Int  // 변수 저장 프로퍼티
        let y: Int  // 상수 저장 프로퍼티 
      }

      정의에서 봤듯이 어떤 대상 - 이경우에는 Point  라는 구조체에 x,y라는 값을 할당해주는 애들이 프로퍼티  입니다.

       

       

      Lazy Stored Properties

      ► lazy라는 키워드를 사용하는 지연 저장 프로퍼티는 호출이 있어야 값을 초기화 합니다.

           그 말은, 값이 처음으로 사용 되기 전에는 계산되지 않는다는 말이죠!

      ► 지연 저장 프로퍼티는 반드시! var로 선언해야 합니다.  let 선언은 초기화가 되기 전에 항상 값을 갖는 프로퍼티이기 때문!!!

      ► 어떨 때 유용할까? 프로퍼티가 특정 요소에 의존적이어서, 그 요소가 끝나기 전에 값을 알 수 없는 경우.

           혹은 복잡한 계산, 부하가 많이 걸리는 작업을 lazy로 선언하면 인스턴스 초기화 시점에 복잡한 계산을 피할 수 있읍니당.

      ► 지연 프로퍼티가 여러 스레드에서 사용되면? 한번만 실행된다는 보장이 x. Thread safe 하지 않음!!

      ► 단일 스레드에서 사용될 경우 초기화는 한 번!

       

      class DataImporter {
          /*
              겁 나 오 래 걸 리 는 초기화 작업
          */
           
          var filename = "data.txt"
      }
      
      class DataManager {
          lazy var importer = DataImporter()
          var data = [String]()
          /*
             데이터를 관리하는 기능
          */
      }
      
      let manager = DataManager()
      manager.data.append("Some data")
      manager.data.append("Some more data")
      // DataImporter 인스턴스는 이 시점에 생성돼 있지 x
      
      //이렇게 직접 importer 인스턴스에 접근할때야 생성됨
      print(manager.importer.filename)

       

       

       

      연산 프로퍼티 (Computed Properties)

      클래스, 구조체, 열거형은 저장 프로퍼티 뿐만 아니라 연산 프로퍼티도 선언할 수 있습니다.

       

      ► 저장 프로퍼티와 다르게 실제 값을 저장하고 있는 것이 아니라, 다른 프로퍼티와 간접적으로 값을 검색하고 세팅합니다

          그게 바로 getter  setter(optional)라는 연산 프로퍼티!

       

      ► 계산값에 따라 값이 변할 수 있는 프로퍼티이기 때문에 항상 var 으로 선언!!!

       

      ►set(newValue) { ... } 와 같은 구조에서 (newValue)라고 인자이름을 지정하지 않아도 기본 이름인 newValue를 사용할 수 있습니다!

       like this

      set {
                  origin.x = newValue.x - (size.width / 2)
                  origin.y = newValue.y - (size.height / 2)
              }

       

      ► 예제 1

      class P {
      	var x: Int {
          		get { return x }
              	set(newValue) { x = newValue * 2 }
          }
      }
      
      var p = Point()
      p.x = 12 		// error!

      이렇게 하면 에러가 납니다!!!!!

      x값이 자기 자신을 리턴하고 자기 자신을 두배로 만들고 있기 때문에 이렇게 사용하면 오류가 납니다.

      그래서 getter setter에는 필수적으로 변수가 더 있어야하는데, 이처럼 내부에서 사용하는 변수용으로 사용하는 stored Property는 언더바를 붙인 형태로 구분합니다. 

      class Test {
      
          private var _myProperty: Int
          
          var myProperty: Int {
              get {
                  return _myProperty
              }
              set {
                  return _myProperty = newValue
              }
          }
      
      }

      ► 예제2

      struct Point {
          var x = 0.0, y = 0.0
      }
      struct Size {
          var width = 0.0, height = 0.0
      }
      
      
      struct Rect {
          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)
              }
          }
      }

      center라는 Point형 변수에 접근할 때는 origin, size라는 다른 프로퍼티를 이용하여 계산하고, center를 직접 설정할 때는 size를 이용해서 origin을 변경하고 있습니다. 

      var square = Rect(origin: Point(x: 0.0, y: 0.0),
                        size: Size(width: 10.0, height: 10.0))
                        
      let initialSquareCenter = square.center	//getter로 square의 center값 가져옴
      square.center = Point(x: 15.0, y: 15.0) //setter로 center값 변경
      
      
      print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
      // "square.origin is now at (10.0, 10.0)" 출력

       

       

      프로퍼티 옵저버 (Property Observers)

      ► 프로퍼티에 새 값이 설정(set)될 때마다 이벤트를 감지할 수 있습니다. 

      ► 지연 저장 프로퍼티(lazy stored properties)에서는 사용할 수 없음!

      ► 연산 프로퍼티는 setter에서 값의 변화를 감지하므로 따로 옵저버를 정의할 필요가 없음!

      ► willSet : 값이 저장되기 바로 직전에 호출 (연산프로퍼티의 set에서와 마찬가지로 기본 값으로 newValue라는 파라미터명 사용)
           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

       

       

       

       

      댓글

    Maybe a whole cake ? 🎂 HAHA!