평소에 노션에 필기한 내용들은 #TodayILearned 해시태그를 붙여 여기 벨로그에 공유하려고 합니다...! 구글이라는 우주에 우주쓰레기마냥 흩어져 있는 개념들을 처리하는 용도로 쓰세요 ゝ。∂)
하이라이트
로 표시했으니참고해 주세요!
또 노트정리 포스팅은 우주쓰레기가 다 정리되는 그 날까지 꾸준히 업로드할 예정이니 많은 관심 부탁드려용
상속과 프로퍼티 오버라이딩을 알아보기 전에..! Swift에서 말하는 '프로퍼티'가 다른 언어와 조금 달라 프로퍼티에 대해 먼저 간략히 설명합니다
상속의 정의에 대한 내용은 다루지 않은 점 참고해주세요!
⭐ Swift에서는 프로퍼티가 저장, 연산 타입 크게 세 가지 프로퍼티 형태로 존재한다.
프로퍼티의 종류
프로퍼티는 구조체, 클래스, 열거형 내부에 구현할 수 있다. 다만 열거형 내부에는 연산 프로퍼티만 구현할 수 있다.
연산 프로퍼티
연산 프로퍼티는 직접 값을 갖지는 않고, 다른 저장 프로퍼티 의 값을 읽어 연산을 실행하거나 프로퍼티의 전달받은 값을 다른 프로퍼티에 저장하는 역할을 한다. 따라서 항상 var로 선언되며 저장 프로퍼티와 달리 저장 공간을 갖지 않는다.
var name: Type {
get { // getter (다른 저장 연산프로퍼티의 값을 얻거나 연산하여 리턴할 때 사용)
statements
return expr
}
set(name) { // setter (다른 저장프로퍼티에 값을 저장할 때 사용)
statements
}
}
연산 프로퍼티를 읽기전용으로는 구현할 수 있지만, 쓰기전용으로는 구현할 수 없다. 읽기전용으로 구현 하려면 get
블럭만 작성해주면 된다. 읽기전용은 get
블럭을 생략할 수 있다. 읽기, 쓰기 모두 가능하게 하려면 get
블럭과 set
블록을 모두 구현해주면 된다.
예) 프로퍼티 사용 예제
struct Student {
// 1. 인스턴스 저장 프로퍼티
var name: String = ""
var `class`: String = "Swift"
var koreanAge: Int = 0
// 2. 인스턴스 연산 프로퍼티
var westernAge: Int {
get {
return koreanAge - 1
}
set(inputValue) {
koreanAge = inputValue + 1
}
}
// 3. 타입 저장 프로퍼티
static var typeDescription: String = "학생"
/*
// 인스턴스 메서드
func selfIntroduce() {
print("저는 \(self.class)반 \(name)입니다")
}
*/
// 읽기전용 인스턴스 연산 프로퍼티
// 간단히 위의 selfIntroduce() 메서드를 대체할 수 있다
var selfIntroduction: String {
get {
return "저는 \(self.class)반 \(name)입니다"
}
}
/*
// 타입 메서드
static func selfIntroduce() {
print("학생타입입니다")
}
*/
// 읽기전용 타입 연산 프로퍼티
// 읽기전용에서는 get을 생략할 수 있다
static var selfIntroduction: String {
return "학생타입입니다"
}
}
예제) 클래스 상속
// 기본 클래스(아무런 상속을 받지 않은 클래스) Person
class Person {
var name: String = ""
func selfIntroduce() {
print("저는 \(name)입니다")
}
// final 키워드를 사용하여 재정의를 방지할 수 있다
final func sayHello() {
print("hello")
}
// 타입 메서드
// 재정의 불가 타입 메서드 - static 키워드
static func typeMethod() {
print("type method - static")
}
// 재정의 가능 타입 메서드 - class 키워드
class func classMethod() {
print("type method - class")
}
// 재정의 가능한 class 메서드라도 final 키워드를 사용하면 재정의 할 수 없다
// 메서드 앞의 `static`과 `final class`는 똑같은 역할을 한다
final class func finalCalssMethod() {
print("type method - final class")
}
}
// Person을 상속받는 Student
class Student: Person {
// 저장 프로퍼티
var major: String = ""
override func selfIntroduce() {
print("저는 \(name)이고, 전공은 \(major)입니다")
}
override class func classMethod() {
print("overriden type method - class")
}
// static을 사용한 타입 메서드는 재정의 할 수 없다
// override static func typeMethod() { }
// final 키워드를 사용한 메서드, 프로퍼티는 재정의 할 수 없다
// override func sayHello() { }
// override class func finalClassMethod() { }
}
static
과 final class
는 같은 역할을 수행한다.상속 받은 프로퍼티의 속성에 대한 (1) getter, setter를 제공하거나(즉 연산 속성을 추가) 값의 변경을 추적할 수 있는 (2) 프로퍼티 옵저버를 추가하는 정도로 알아두자.
class Human {
var name = "Sodeul" // 저장 프로퍼티
var alias: String { // 연산 프로퍼티가 getter로만 구현된 경우
return self.name + " 바보"
}
}
class Teacher: Human {
// 저장 속성을 추가하면 컴파일 에러 발생
override var name: String = "Sodeul2"
}
class Teacher1: Human {
var alias = "SodeulSodeul"
// 연산 속성을 추가해주는 오버라이딩은 가능
override var name: String {
get {
return self.alias
}
set {
self.alias = newValue
}
}
}
1) getter, setter 제공하기
2) 프로퍼티 옵저버 추가하기
willSet
블럭이, 값이 변경된 직후에 didSet
블럭이 호출된다. 둘 중 필요한 하나만 구현해 주어도 무관하다. 변경 되려는 값이 기존 값과 똑같더라도 프로퍼티 감시자는 항상 동작한다. willSet
블럭에서 암시적 매개변수 newValue
를 사용할 수 있고, didSet
블럭에서 암시적 매개변수 oldValue
를 사용할 수 있다.var currencyRate: Double = 1100 {
willSet(newRate) {
print("환율이 \(currencyRate)에서 \(newRate)으로 변경될 예정입니다")
}
didSet(oldRate) {
print("환율이 \(oldRate)에서 \(currencyRate)으로 변경되었습니다")
}
}
본 포스팅은 야곰 님의 '스위프트 기본 문법' 강의를 토대로 작성되었습니다. 질문과 피드백은 언제나 환영입니다. 부족하거나 틀린 부분은 편하게 말씀해주시면 감사하겠습니다!