Swift 뿌수기 - Properties

Wonbi·2022년 8월 26일
2

Swift 뿌수기

목록 보기
6/12

✅학습 내용

💎 프로퍼티

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. Computed properties are provided by classes, structures, and enumerations. Stored properties are provided only by classes and structures.

  • 프로퍼티 (properties)는 값을 특별한 클래스, 구조체, 또는 열거체와 결합합니다. 저장 프로퍼티는 인스턴스의 일부분으로써 상수와 변수 값을 저장하는 반면, 연산 프로퍼티는 값을 (저장한다기 보단) 계산합니다. 연산 프로퍼티는 클래스, 구조체, 및 열거체에서 제공합니다. 저장 프로퍼티는 클래스와 구조체에서만 제공합니다.

  • 지금까지 클래스와 구조체 내에서 선언했던 변수와 상수가 바로 프로퍼티이다.

  • 하지만 정확한 표현은 아닌것이, Swift내 프로퍼티는 3가지 종류의 프로퍼티가 있다. 사실 이거말고 더 있긴 한거 같은데 일단
    1. Stored Property: 저장 프로퍼티
    2. Computed Property: 연산 프로퍼티
    3. Type Properties: 타입 프로퍼티

  • 저장 프로퍼티와 연산 프로퍼티는 타입의 인스턴스에 결합되어 사용되지만, 타입 프로퍼티는 타입 그 자체와 결합되어 사용된다.

  • 이 외에도 프로퍼티 관찰자 (property observers) 를 정의할 수 있다. 이는 이름 그대로 프로퍼티 값의 변화를 관찰 하는 것으로, “저장 프로퍼티”에 추가할 수 있다. 새 값의 속성이 현재 값과 동일하더라도, 속성 값이 설정되면 호출된다.

  • 프로퍼티 포장 (property wrapper) 을 사용하여 여러 속성에서 획득자 (getter) 와 설정자 (setter) 코드를 재사용할 수도 있다.

✏️ 1. Stored Property: 저장 프로퍼티

  • 저장 프로퍼티는 클래스와 구조체에서만 사용할 수 있고, 값을 저장하기 위해 선언되는 상수/변수를 의미한다.

  • 즉 우리가 프로퍼티라고 알고 있던것은 정확하게 말하자면 저장 프로퍼티였던 것.

struct FixedLengthRange {
  var firstValue: Int
  let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 이 범위는 정수 값 0, 1, 2 를 나타냄
rangeOfThreeItems.firstValue = 6
// 이제 범위는 정수 값 6, 7, 8 을 나타냄

✏️ 2. Lazy Stored Property: 지연 저장 프로퍼티

  • 프로퍼티가 호출되기 전까지는 선언만 될 뿐 초기화되지 않고 있다가, 프로퍼티가 호출되는 순간에 초기화 되는 저장 프로퍼티이다.

  • 원래 기본적으로 모든 프로퍼티는 이니셜라이저가 선언되는 순간 모두 초기화 되어야 하는데, 이 지연 저장 프로퍼티는 이니셜라이저가 불릴 때 초기화가 되어있지 않더라도 오류가 나지 않는다.

  • 바로 코드가 이 값에 접근할 때 초기화가 진행된다.

  • 이러한 특성 때문에 지연 저장 프로퍼티는 무조건 변수로만 선언이 가능하다. 그 이유는 이제 말하지 않아도 알 것이다.

  • 지연 저장 프로퍼티는 필요할 때만 초기화를 시킬 수 있는 장점이 있기 때문에 많은 인스턴스를 만들더라도 메모리를 효율적으로 관리할 수 있는 장점이 있다.

class DataImporter {
  /*
  DataImporter 는 외부 파일에서 자료를 불러오는 클래스입니다.
  이 클래스의 초기화에는 유의미한 양의 시간이 걸린다고 가정합니다.
  */
  var filename = "data.txt"
  // DataImporter 클래스는 여기서 자료 불러오는 기능을 제공할 것임
}

class DataManager {
  lazy var importer = DataImporter()
  var data = [String]()
  // DataManager 클래스는 여기서 자료 관리 기능을 제공할 것임
}

let manager = DataManager()
manager.data.append("Some data")
manager.data.append("Some more data")
// importer 속성의 DataImporter 인스턴스는 아직 생성하지 않음

✏️ 3. Computed Property: 연산 프로퍼티

  • 연산 프로퍼티는 저장 프로퍼티와는 다르게 저장 공간을 가지지 않고, 다른 저장 프로퍼티의 값을 읽어 연산을 실행하거나, 프로퍼티로 전달받은 값을 다른 프로퍼티에 저장한다.

  • 위와 같은 특성 때문에 변수로만 할당해야 한다. 다른 값을 가져와 연산하여 새로운 값을 뱉어내는 구조이기 때문.

class Person {
    var nickname: String {
        get {			 //getter (다른 저장 연산프로퍼티의 값을 얻거나 연산하여 리턴할 때 사용)
            return alias
        }
        set(name) {		//setter (다른 저장프로퍼티에 값을 저장할 때 사용)
            self.alias = name
        }
    }
}
  • 연산 프로퍼티는 특정 값을 저장하는 것이 아니기 때문에 타입추론이 불가능하다. 따라서 반드시 타입 어노테이션을 해줘야 한다.

  • 선언된 프로퍼티 뒤에 대괄호{}를 붙이는 것이 연산 프로퍼티의 사용법.

  • getter는 말 그대로 “얻는” 것이다. 따라서 어떤 저장 프로퍼티의 값을 연산해서 return할 것인지. return구문이 반드시 존재해야 한다.

  • setter는 말 그대로 “설정” 하는 것이다. 따라서 파라미터로 받은 값을 어떤 저장 프로퍼티에 어떻게 설정할 것인지 구현해줘여 한다.

  • 따라서 사실 위 예제는 틀린 예제이다. 왜냐하면, get, set구문에서 연산 프로퍼티의 값을 가져오려하기 때문. 연산 프로퍼티는 반드시 저장 프로퍼티의 값을 가져오도록 해야 한다.

class Person {
    var name: String = “wonbi”
 
    var nickname: String {
        get {
            return name
        }
        set(name) {
            self.name = name
        }
    }
}
  • 다음과 같이 사용해야만 한다.

class Person {
    var name: String = “wonbi”
 
    var nickname: String {
        get {
            return self.name + " 는 이름”
        }
        set(name) {
            self.name = name + “는 닉네임”
        }
    }
}

let wonbi: Person = .init()
 
// get에 접근
print(wonbi.nickname)        // wonbi 는 이름
 
// set에 접근
wonbi.nickname = “원비디”
print(sodeul.name)              // 원비디는 닉네임
  • 연산 프로퍼티인 nickname값을 읽으면, nicknameget이 실행되어 “wonbi 는 이름” 이라는 값이 나온 것이고
    연산 프로퍼티인 nickname에 값을 쓰면, “원비디”라는 값이 set의 파라미터로 넘어가 set함수가 실행된다.

  • set함수의 매개변수는 왜 타입을 명시해주지 않을까? 그것은 이미 nickname이라는 연산 프로퍼티를 선언 할 때 타입을 명시해주었기 때문이다.

  • 위 예제에서는 set의 매개변수 이름을 name으로 했지만, 다른이름으로 지어도 상관없다. 대신 단 하나의 매개변수만 존재한다는 사실을 기억하자.

  • get구문 처럼 set구문의 매개변수를 아예 생략해버릴 수도 있다. 대신 매개변수에 접근하려면 newValue라는 이름으로 접근하면 된다. 반드시 newValue로만 접근해야함.

  • get-only로 사용할 수도 있는데 단순히 set구문을 쓰지 않으면 된다. 더 간단하게 get문도 삭제하고 return만 써도 된다.

  • set-only는 불가능. 무조건 get구문을 써줘야만 한다.

0개의 댓글