모바일/SwiftUI ios 공부

상속, 슈퍼 클래스, 베이스 클래스, 부모 클래스, 타입캐스팅 연산자 is, as/ Xcode SwiftUI Playground 공부

yy_dd2 2021. 11. 28. 16:06
반응형

부모가 자식에게 재산을 물러주는 행위

 

베이스 클래스, 슈퍼 클래스, 부모 클래스 : 다른 클래스에게 상속받지 않은 클래스

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)")
    }
}

 

반응형