Skip to content

Latest commit

 

History

History
executable file
·
199 lines (152 loc) · 8.84 KB

[스위프트 대충보기] 9. 프로퍼티(property).md

File metadata and controls

executable file
·
199 lines (152 loc) · 8.84 KB
Error in user YAML: (<unknown>): did not find expected key while parsing a block mapping at line 1 column 1
---
layout: post
title: [스위프트 대충보기] 9. 프로퍼티(property)
tags: 스위프트, swift, 클래스, 구조체, class, struct
---

[스위프트 대충보기] 9. 프로퍼티(property)

프로퍼티

  • 프로퍼티: 클래스, 구조체, 열겨형에 들어있는 값.

    • 저장(stored) 프로퍼티: 인스턴스의 일부분으로 메모리에 보관함

    • 계산(computed) 프로퍼티: (인스턴스의 상태를 바탕으로) 계산해서 값을 내놓음

  • 인스턴스의 프로퍼티가 있고, 타입의 프로퍼티가 있음

  • 프로퍼티 값의 변화를 감시하는 프로퍼티 옵저버(property observer)를 만들 수 있음

저장 프로퍼티(stored property)

  • 가장 간단한 저장 프로퍼티: 클래스/구조체 안에 들어있는 상수 또는 변수

    • 디폴트 프로퍼티 값: 클래스/구조체 정의 내부에서 프로퍼티를 정의할 때 사용한 값

    • 초기화 함수를 통해 프로퍼티의 값을 변경할 수 있음. 이때, 상수 프로퍼티의 값도 지정 가능(!).

    • 변수 프로퍼티는 인스턴스 생애동안 변경 가능하지만, 상수 프로퍼티는 초기화 하고 나면 변경 불가

        struct FixedLengthRange {
            var firstValue: Int
            let length: Int
        }
        var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
        rangeOfThreeItems.firstValue = 6
      
  • 구조체 인스턴스를 상수 변수에 지정한 경우: 구조체 인스턴스를 상수 변수에 대입하면, 그 구조체의 프로퍼티는 절대 바꿀 수 없다(var로 선언한 프로퍼티 조차도!). 구조체가 값타입이어서 그렇다. 반면, 클래스는 레퍼런스기 때문에, 상수 레퍼런스는 바꿀 수 없지만, 인스턴스의 상태는 변경 가능하다.

          let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
          rangeOfFourItems.firstValue = 6 // 오류!
    

지연저장 프로퍼티

  • 지연 저장 프로퍼티(lazy stored property): 초기값을 해당 프로퍼티를 실제 사용하기 전까지 계산하지 않는 프로퍼티. var만 lazy로 선언 가능.

    • 계산이 시간이 오래 걸리는 경우 사용하거나,

    • 인스턴스 생성 시점에는 계산에 필요한 정보를 아직 다 얻을 수 없는 경우 사용한다.

        class DataImporter {
            /* 외부 파일에서 데이터를 가져오는 시간이 무지하게 걸리는 클래스 */
            var fileName = "data.txt"
        }
      
        class DataManager {
            @lazy var importer = DataImporter()
            var data = String[]()
        }
      
        let manager = DataManager()
        manager.data += "Some data"
        manager.data += "Some more data"
      
  • Objective-C와 달리 인스턴스 변수와 프로퍼티가 동일하다. 스위프트에서는 프로퍼티만을 사용한다.

    • 스위프트 프로퍼티는 내부 변수를 따로 만들 필요가 없다. 컴파일러가 알아서 처리한다.
    • 프로퍼티의 특성을 소스코드의 여기저기 흩어놓지 않고 한군데 모아 놓는다.

계산 프로퍼티

  • 계산 프로퍼티: 실제로는 저장해 둔 값이 아니고, 게터(getter)에서 값을 계산해 반환하고, 세터(setter)를 통해 간접적으로 값 계산과 관련 있는 대상에 영향을 끼칠 수 있다

          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(newCenter) {
                  origin.x = newCenter.x - (size.width / 2)
                  origin.y = newCenter.y - (size.height / 2)
              }
              }
          }
          var square = Rect(origin: Point(x: 0.0, y: 0.0),
              size: Size(width: 10.0, height: 10.0))
          let initialSquareCenter = square.center
          square.center = Point(x: 15.0, y: 15.0)
          println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
    
  • 세터(변수이름)처럼 변수이름을 지정하지 않고 기본 이름인 newValue를 사용해 더 짧게 작성 가능하다.

          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)
              }
              }
          }
    
  • 읽기전용 계산 프로퍼티: 세터가 필요 없는 경우 get이라고 쓰지 않고, 바로 게터 코드를 프로퍼티 본체에 넣을 수 있다.

          struct Cuboid {
              var width = 0.0, height = 0.0, depth = 0.0
              var volume: Double {
              return width * height * depth
              }
          }
          let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
          println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
    

프로퍼티 옵저버(observer)

  • 프로퍼티 옵저버: 프로퍼티 값의 변화를 감지하고 대응한다. 스위프트는 프로퍼티 값이 변할(프로퍼티에 값을 대입할) 때마다 옵저버를 호출해 주며, 이전 값과 같은 값을 대입하는 경우에도 호출한다.

  • 지연 저장 프로퍼티가 아닌 모든 저장 프로퍼티에 옵저버를 설정 가능하다. (계산 프로퍼티는 언제 계산이나 수정이 되는지 코드가 다 알 수 있으므로 옵저버를 제공하지 않는다.)

  • 상속해 오버라이드한 프로퍼티는 계산이나 저장 여부와 관계 없이 옵저버 설정 가능하다.

    • willSet : 값 저장 직전 호출. 새로 변경할 값을 상수 인자로 받음. 이름을 지정하지 않으면 newValue라는 이름이 디폴트

    • didSet : 값 저장 직후 호출. 옛날 값을 상수 인자로 받음. 이름을 지정하지 않으면 oldValue라는 이름이 디폴트

        class StepCounter {
            var totalSteps: Int = 0 {
            willSet(newTotalSteps) {
                println("About to set totalSteps to \(newTotalSteps)")
            }
            didSet {
                if totalSteps > oldValue  {
                    println("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 출력
      
  • 전역변수와 지역변수에도 옵저버를 적용 가능

타입 프로퍼티

  • 타입 프로퍼티: 인스턴스 프로퍼티와 달리 클래스/구조체 등의 특정 타입의 프로퍼티(C의 static) : static을 붙여서 지정(구조체, 열거형)하거나 class를 붙여서 지정(클래스)

          struct SomeStructure {
              static var storedTypeProperty = "Some value."
              static var computedTypeProperty: Int {
              // return an Int value here
              }
          }
          enum SomeEnumeration {
              static var storedTypeProperty = "Some value."
              static var computedTypeProperty: Int {
              // return an Int value here
              }
          }
          class SomeClass {
              class var computedTypeProperty: Int {
              // return an Int value here
              }
          }
    
  • 타입 프로퍼티는 "타입이름.프로퍼티이름"으로 사용함

          println(SomeClass.computedTypeProperty) // 42 출력
          println(SomeStructure.storedTypeProperty) // "Some value."출력
          SomeStructure.storedTypeProperty = "Another value."
          println(SomeStructure.storedTypeProperty) // "Another value." 출력
    
  • 타입 프로퍼티에도 didSet, willSet 설정 가능

  • 어떤 프로퍼티의 옵저버 안에서 그 프로퍼티의 값을 변경하는 경우에는 스위프트가 다시 옵저버를 호출하지 않음