상속, 슈퍼 클래스, 베이스 클래스, 부모 클래스, 타입캐스팅 연산자 is, as/ Xcode SwiftUI Playground 공부
부모가 자식에게 재산을 물러주는 행위
베이스 클래스, 슈퍼 클래스, 부모 클래스 : 다른 클래스에게 상속받지 않은 클래스
class Vehicle {
var currentSpeed = 0.0
//final var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
print("speaker on")
}
}
// 코드의 주석에 final 설명
final : 자식 클래스에서 메소드, 프로퍼티 등이 재정의되는 것을 방지하기 위해 ‘final’ 키워드를 사 용합니다.
- final로 선언된 요소들은 직접 호출하는 반면에, 그렇지 않은 요소들은 vtable을 통해 간접 호 출되어 직접 호출되는 경우보다 느리게 작동한다고 한다
- vtable : 가상 메소드 테이블이며, 메소드 오버라이딩에 따라 실행 시점에 어떤 메소드를 실행 할지 결정하는 동적 디스패치를 지원하기 위해 프로그래밍 언어에서 사용하는 메커니즘입니다.
서브클래싱 Subclassing
● 서브클래싱 : 기존 클래스(베이스)를 상속받아 새로운 클래스(자식)를 만드는 행위
● 자식 클래스에서는 부모 클래스의 프로퍼티, 메소드를 상속 받을 수 있으며, 자기 자신의 고유의 특성도 추가가 가능함.
● 자식 클래스를 정의하려면 " : " 뒤에 부모 클래스 이름을 작성하면 된다.
class 클래스 이름: 부모클래스 이름 {
// 하위 클래스 정의
}
class Bicycle: Vehicle {
var hasBasket = false
}
var bicycle = Bicycle()
bicycle.currentSpeed // 0
bicycle.currentSpeed = 15.0
bicycle.currentSpeed // 15
오버라이딩 Overriding
● 오버라이딩 : 자식 클래스에서는 부모 클래스에서 상속받은 것을 재정의 할 수 있다
● 오버라이딩은 인스턴스 메소드, 타입 메소드, 인스턴스 프로퍼티, 타입 프로퍼티, 서브스크립트 모두에 대해서 사용 가능함.
● 오버라이드를 위해서는 다른 선언 앞에 override 키워드를 붙인다 (키워드를 안붙이면 컴파일러 오류남)
class Train: Vehicle {
override func makeNoise() {
// 필요에 따라 슈퍼 클래스에 정의된 함수를 먼저 실행할 수 있다. 슈퍼 클래스에 정의된 makeNoise()가 실행된 다음에 실행됨
super.makeNoise()
print("choo choo")
}
}
let train = Train()
train.makeNoise() // "choo choo"
코드 실행 결과
speaker on
choo choo
프로퍼티 오버라이딩 방법
메서드와 마찬가지로 슈퍼클래스로 부터 상속받은 인스턴스 프로퍼티, 타입 프로퍼티를 서브 클래스의 용도에 맞게 재정의 할 수 있다
프로퍼티 재정의 : 프로퍼티의 get,set 프로퍼티 옵저버를 재정의하는 것
// 자동차 클래스 선언
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + "in gear \(gear)"
}
}
let car = Car()
car.currentSpeed = 30.0
car.gear = 2
print(car.description)
코드 실행 결과
traveling at 30.0 miles per hourin gear 2
슈퍼클래스에 있는 프로퍼티 서브클래스에서 재정의
- 계산 프로퍼티 저장 프로퍼티를 오버라이딩한 프로퍼티는 겟터 셋터를 가질 수 있다
- 자식 클래스에서 재정의하려는 프로퍼티는 슈퍼클래스 프로퍼티의 이름과 타입이 일치해야한다
- 슈퍼클래스에서 readwrite 선언된 프로퍼티를 서브클래스에서 readonly 오버라이드 할 수는 없다
- 슈퍼클래스에서 readonly 선언된 프로퍼티는 readwrite로 오버라이드 할 수 있다.
// 상속된 프로퍼티에 오버라이드를 사용해서 프로퍼티에 옵저버도 추가하기
class AutomaticCar: Car {
override var currentSpeed: Double{
didSet {
gear = Int(currentSpeed / 10) + 1
}
}
}
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
/* 프로퍼티 재정의로 :currentSpeed 값이 변경되면 프로퍼티 옵저버를 통해서 gear 프로퍼티의 값이 변경되게 사용도 가능하다.
상속된 오버라이드를 사용하면 프로퍼티 옵저버를 추가 할 때는 상수 저장 프로퍼티나 readonly 연산 프로퍼티는 프로퍼티 옵저버를 추가할 수 없다 (값을 설정할 수 없기 때문에 리셋이나 디드셋을 사용할 수 없다)
*/
코드 실행 결과
AutomaticCar: traveling at 35.0 miles per hourin gear 4
이미 공부를 한적이 있는듯 하지만 상속부분과 같이 보는게 좋을거 같아 다시 작성
https://tog-code.tistory.com/79?category=409980
타입캐스팅 연산자
타입캐스팅 ?
인스턴스의 타입을 확인하거나 어떠한 클래스의 인스턴스를 해당 클래스 계층구조의 슈퍼(부모)클래스나 서브(자식)클래스로 취급하는 방법
//import UIKit
import Foundation
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
// MediaItem 상속하는 Movie 클래스
class Movie:MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
let library = [
Movie(name: "영화제목1", director: "감독이름A"),
Song(name: "노래제목1", artist: "가수이름1"),
Movie(name: "영화제목2", director: "감독이름B"),
Song(name: "노래제목2", artist: "가수이름2"),
Song(name: "노래제목3", artist: "가수이름3")
]
// 해당 아이콘이 무비클래스인지 송클래스인지 확인하기
var movicCount = 0
var songCount = 0
// item에 따라서 어떤 클래스인지 카운트가 증가하도록 구현
for item in library {
if item is Movie {
movicCount += 1
} else if item is Song {
songCount += 1
}
}
// Media library contains 2 movies and 3 songs
print("Media library contains \(movicCount) movies and \(songCount) songs")
// 인스턴스의 타입이 어떤 타입인지 확인 가능하다
다운캐스팅
- 특정 클래스 타입의 상수, 변수 하위 클래스의 인스턴스를 참조할 수 있다.
--> 코드에서 라이브러리 배열같이 MediaItem으로 선언된 배열을 다운캐스팅을 이용해 MediaItem의 서브클래스인 Movie,Song 인스턴스를 참조할 수 있다는 말 이 경우 타입캐스팅 연산자로 as? as!로 서브클래스 타입으로 다운캐스팅 형변환 시도를 할 수 있다.
- 다운캐스팅은 실패할 수 있기 때문에 타입캐스팅 연산자는 두가지 형태로 제공됨
- as? : 조건부 형식으로 다운캐스팅 하려는 옵셔널 값으로 반환된다
- as! : 강제 형식으로 강제로 언랩핑해서 값을 반환한다 (항상 성공 할 것이라 확신할 떄만 사용해야함 타입이 맞지 않으면 프로그램 강제종료 될 수 있음)
for item in library {
if let movie = item as? Movie {
print("Movie: \(movie.name), dir. \(movie.director)")
} else if let song = item as? Song {
print("Song: \(song.name), by \(song.artist)")
}
}