---
layout: post
title: [스위프트 대충보기] 9. 프로퍼티(property)
tags: 스위프트, swift, 클래스, 구조체, class, struct
---
-
프로퍼티: 클래스, 구조체, 열겨형에 들어있는 값.
-
저장(stored) 프로퍼티: 인스턴스의 일부분으로 메모리에 보관함
-
계산(computed) 프로퍼티: (인스턴스의 상태를 바탕으로) 계산해서 값을 내놓음
-
-
인스턴스의 프로퍼티가 있고, 타입의 프로퍼티가 있음
-
프로퍼티 값의 변화를 감시하는 프로퍼티 옵저버(property observer)를 만들 수 있음
-
가장 간단한 저장 프로퍼티: 클래스/구조체 안에 들어있는 상수 또는 변수
-
디폴트 프로퍼티 값: 클래스/구조체 정의 내부에서 프로퍼티를 정의할 때 사용한 값
-
초기화 함수를 통해 프로퍼티의 값을 변경할 수 있음. 이때, 상수 프로퍼티의 값도 지정 가능(!).
-
변수 프로퍼티는 인스턴스 생애동안 변경 가능하지만, 상수 프로퍼티는 초기화 하고 나면 변경 불가
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)")
-
프로퍼티 옵저버: 프로퍼티 값의 변화를 감지하고 대응한다. 스위프트는 프로퍼티 값이 변할(프로퍼티에 값을 대입할) 때마다 옵저버를 호출해 주며, 이전 값과 같은 값을 대입하는 경우에도 호출한다.
-
지연 저장 프로퍼티가 아닌 모든 저장 프로퍼티에 옵저버를 설정 가능하다. (계산 프로퍼티는 언제 계산이나 수정이 되는지 코드가 다 알 수 있으므로 옵저버를 제공하지 않는다.)
-
상속해 오버라이드한 프로퍼티는 계산이나 저장 여부와 관계 없이 옵저버 설정 가능하다.
-
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 설정 가능
-
어떤 프로퍼티의 옵저버 안에서 그 프로퍼티의 값을 변경하는 경우에는 스위프트가 다시 옵저버를 호출하지 않음