swift study 11. 속성(property)

jess·2022년 7월 14일
0

Swift

목록 보기
11/19
post-thumbnail

🍃 앨런 swift 문법 마스터 스쿨 수업을 듣고 제가 이해한대로 정리해서 올리는 포스팅입니다.

  • 속성 (property) : 구조체 / 클래스의 변수
    (클래스, 구조체, 열거형과 연관되어 있는 정보 / 값 등을 의미)
struct Bird {
    var name: String
    var weight: Double
}

📓 속성 (property)

  • 속성(프로퍼티)은 총 3가지 형태로 존재한다.
    1) 저장 속성 (저장 프로퍼티)
    2) 계산 속성 (연산 프로퍼티)
    3) 타입 속성 (타입 프로퍼티)

1) 저장 속성 (stroed properies)

  • 값을 저장하기 위해 선언되는 상수/변수
  • 구조체 / 클래스 (열거형X)
struct Bird {
    var name: String
    var weight: Double
    init(name: String, weight: Double) {
        self.name = name
        self.weight = weight
    }
    func fly() {
        print("날아갑니다.")
    }
}
  • Bird라는 클래스에 저장된 name이란 변수, weight라는 변수 모두 저장 프로퍼티
  • 클래스 / 구조체의 틀에서 찍어낸 각 인스턴스가 가지는 고유의 데이터 저장 공간 (고유 메모리 공간)
  • 변수(var)나 상수(let)로 선언 가능
  • 객체의 초기화 시, 각 저장 속성은 반드시 값을 가져야 한다. 즉, 초기화 이전에 값을 가지고 있거나, 생성자 메서드를 통해 값을 반드시 초기화 해야 함
  • 기본값 설정하거나 또는 생성자에서 설정, 또는 옵셔널 타입으로 선언하여 nil을 초기값으로 갖는 것 가능

1-1) 지연 저장 속성 (lazy stored properties)

  • 해당 저장 속성의 초기화를 지연시키는 것
  • 즉, 인스턴스가 초기화되는 시점에 해당 속성이 값을 가지고 초기화 되는 것이 아니라 (메모리에 공간과 값을 갖는 것이 아니라)
    해당 속성(변수)에 접근하는 순간에 개별적으로 초기화 하는 것
  • 따라서, 상수로의 선언은 안되고 변수로의 선언만 가능 (lazy var)
struct Bird {
    var name: String
    lazy var weight: Double = 0.2
    init(name: String) {
        self.name = name
    }
    func fly() {
        print("날아갑니다.")
    }
}
var aBird = Bird(name:"새")
  • weight 라는 속성은 초기화 시점에 메모리 공간이 생기는 것이 아님
 ✨ 주의점
  - 지연 저장 속성은 선언시점에 기본값을 저장, 구조체와 클래스 동일
  - 저장하려는 속성과 리턴형만 일치한다면 
  함수 호출코드, 계산코드, 클로저 코드 등도 모두 가능
 ✨ 사용하는 이유
  1) 메모리를 많이 차지할 때
  2) 다른 저장 속성에 의존해야 할 때 

2) 계산속성 (computed properties) _ 연산속성/프로퍼티

  • 구조체 / 클래스 / (열거형)
class Person {
    var name = "사람"
    var h = 160.0
    var w = 45.0
    var bmi: Double {
        get {
            return w / (h*h) * 10000
        }
        set {
            w = newValue * h * h / 10000
        }
    }
}
var p = Person()
p.bmi          // get ➡️ 밖에서 접근해서 값을 얻기
p.bmi = 23.4   // set ➡️ 밖에서 값을 세팅하기 

1) getter (get블록) : 값을 얻기 위한 것
2) setter (set블록) : 값을 세팅하기 위한 것 (선택적 구현)

  • 속성의 형태를 가진 실질적 메서드
  • 메서드이기에 인스턴스에 메모리 공간이 할당되어있지 않음
  • var 로만 선언 가능, 자료형까지 선언해야 함 (타입 추론 안됨)
    ➡️ 어떠한 값을 저장하는 것이 아니기 때문에 타입 추론을 통해 형식을 알 수 없기 때문
    따라서, 내가 어떤 타입의 값을 받아서 다른 저장 프로퍼티에 저장할 것인지,
    어떤 타입의 값을 리턴할 것인지를 명시에 주어야 한다
  • get 블록만 선언하면 읽기전용 (read-only) 계산속성이 된다 (필수구현)
  • set 블록은 선택적 구현 (set만 구현은 불가)
  • set 블록에서 기본 파라미터 newValue가 제공됨 (직접 파라미터 이름 설정도 가능)

예시

class Person {
    var birth: Int = 0                // let안됨! (값이 고정되므로) 
    var age: Int {
        get {
            return 2021 - birth
        }
        set {                  
               // 위에 타입을 정의해 놓았으므로 타입정의 안해도 됨
            self.birth = 2021 - newValue
        }
    }
}
var p = Person()
p.birth = 2000
p.age             //get 
p.age = 20        //set 
p.birth
- birth와 같이 읽거나 쓸 수 있는 저장속성이 먼저 존재해야 하고,
  계산속성에서는 이 다른 "저장속성"의 값을 읽거나 쓰는 작업을 해야 한다. 
- set의 파라미터 이름을 짓기 힘들다면 get처럼 파라미트 받는 부분을
  날리고, newValue 라는 이름으로 접근하면 됨 

3) 타입속성 (Type property, 형식속성)

1) 저장 타입 속성
2) 계산 타입 속성

  • 저장 & 계산 속성 앞에 "static"이라는 키워드만 붙이면 저장 타입속성, 계산 타입 속성이 되는 것
  • 인스턴스에 속한 속성이 아니고, 타입자체에 속한 속성이기에 내/외부에서 Type.property로 접근해야함
    (인스턴스가 생성된다고 타입속성이 매번 생성되는 것이 아니라, 호출했을 때 메모리에 한 번 올라가고
    그 뒤로는 어디서든 해당 속성을 <공유> 하는 형태)
  • 저장 타입 속성을 주로 사용
  • static (고정적인/고정된) 이라는 키워드를 추가한 저장 속성
class Dog {
    static let species: String = "Dog"
    var name: String
    var weight: Double
    init (name: String, weight: Double) {
        self.name = name
        self.weight = weight
    }
}
let dog = Dog(name: "초코", weight: 15.0)
dog.name
dog.weight
Dog.species       // Dog(반드시 타입(형식)의 이름으로 접근해야 함)

3-1) 저장 타입 속성

class Circle {
    static let pi = 3.141626
    static var count = 0
    ...
}
- 모든 인스턴스가 동일하게 가져야 하는 보편적인 속성이거나, 
  모든 인스턴스가 공유해야 하는 성격에 가까운 저장속성을 저장 타입 속성으로 선언
- static 키워드 사용. (상속시) 재정의 불가 
  (메서드만 상속 가능 - class 키워드 사용 불가)
- let / var 

3-2) 계산 타입 속성

class Circle {
    static let pi = 3.141526
    ...
    static var multiPi: Double {
        return pi * 2
    }
}
- (상속 시) 재정의 가능 (class 키워드 사용 시에만)
- static 또는 class 키워드 사용 
  (static 상속 시 재정의 불가/class 상속 시 재정의 가능)
- var 키워드만 사용 가능 (계산 타입 속성)
- 메서드이기 때문에 타입에 메모리 공간이 할당되어 있지 않음 (계산 속성)

4) 속성 감시자 (property observer)

✨ (저장) 속성 감시자
1) willSet : 값이 저장되기 직전에 호출된다
2) didSet : 새 값이 저장된 직후에 호출된다

  • 속성 값의 변화를 관찰하는 것으로, 저장 속성에 추가할 수 있다
  • (저장) 속성 감시자 ➡️ 저장 속성을 감시한다, 관찰한다 👀 (성격은 메서드)
  • 내가 관찰하는 속성에 누가 값을 설정하려고 한다? 🚨 프로퍼티 변경 감지하며 알람
  • 구조체 / 클래스 / (열거형)

4-1) willSet

var name: String = "Unknown" {
    willSet(newName) {
        print("현재 이름 = \(name), 바꿀 이름 = \(newName)")
    }
}

✨ willSet 옵저버는 저장속성에 위와 같이 구현한다.
값이 저장되기 <직전> 에 새로 저장될 값이 <파라미터> 로 전달된다
값이 변경되기 전에 호출되는것이라 현재 name 은 아직 Unkown 값
newName이라는 파라미터 이름을 내가 직접 지정해서 위처럼 사용할 수 있으나
newValue의 사용 역시 가능 ⬇️

var name: String = "Unknown" {
    willSet {
        print("현재 이름 = \(name), 바꿀 이름 = \(newValue)")
    }
}

4-2) didSet

var name: String = "Unknown" {
    didSet(oldName) {
        print("현재 이름 = \(name), 바뀌기 전 이름 = \(oldName)")
    }
}

✨ didSet 옵저버는 저장속성에 위와 같이 구현한다.
값이 저장된 <직후> 에 이전 속성의 값이 파라미터로 전달
그래서 name은 변경 된 값, 이전에 저장되어 있던 Unknown값이
파라미터 oldValue로 넘어온 것
oldName이라는 파라미터 이름을 내가 직접 지정해서 위처럼 사용할 수 있으나
oldValue의 사용 역시 가능 ⬇️

   var name: String = "Unknown" {
    didSet {
        print("현재 이름 = \(name), 바뀌기 전 이름 = \(oldValue)")
    }
}

4-3) willSet & didSet

class Profile {
    ...
    var sMessage: String = "기본메시지" {
        willSet {
            print("\(sMessage)=>\(newValue)")   
            // (값이 변할 때) 새 값이 저장되기 직전에 호출한다
        }
        didSet {
            print("\(oldValue)=>\(sMessage)")
            // (값이 변할 때) 새 값이 저장되기 직후에 호출한다
        }
    }
    ...
}
- var 로만 선언 가능 (let은 관찰할 필요 없음)
- 자료형 선언은 일반 변수와 동일 (형식 추론 가능)
- 변수가 변하면, (무엇인가) 업데이트 하려는 패턴을 구현할 때 사용
  ex) 상태메시지, 프로필 사진 서버에서의 변화 ➡️ (바로) 화면 업데이트 

0개의 댓글