- 상속은 클래스, 프로토콜에서 가능하고 열거형, 구조체는 불가능
- 다중상속 ❌, 단일상속만 가능
class 이름: 상속받을 클래스 이름 {
// 구현 및 재정의
}
클래스 이름 뒤에 [ : ] 키워드 이후 상속받고자 하는 클래스 이름을 쓰면 된다.
class Person {
var name: String = ""
func selfIntroduce() { // 재정의 가능
print("저는 \(name)입니다.")
}
final func sayHello() { // 재정의 불가
print("Hello")
}
static func typeMethod() { // 제정의 불가 타입 메서드
print("Type Method - static")
}
class func classMethod() { // 재정의 가능 타입 메서드
print("Type Method - class")
}
final class func finalClassMethod() { // 재정의 불가
print("Type Method - final class")
}
}
class Student: Person{
var major: String = ""
override func selfIntroduce() {
print(" 저는 \(name)이고 전공은 \(major)입니다.")
}
override class func classMethod() {
print("overriden class method")
}
}
- final 키워드 - override 불가 = 자식 클래스가 재정의 불가
- static 메서드 - 재정의 불가 타입 메서드
- class 메서드 - 재정의 가능 타입 메서드
- class 메서드라도 final 키워드가 붙으면 재정의 불가
final class = static
저장 프로퍼티는 재정의가 불가능하다.
부모 클래스의 함수를 호출하고 싶으면 super 키워드를 이용해 [ super.selfIntroduce() ]로 불러올 수 있다.
let human: Person = Person()
let jane: Student = Student()
human.name = "saram"
jane.name = "jane"
jane.major = "iOS"
human.selfIntroduce()
// 저는 saram입니다.
jane.selfIntroduce()
// 저는 jane이고 전공은 iOS입니다.
Person.classMethod()
// ype Method - class
Student.classMethod()
// overriden class method
Student.typeMethod()
// Type Method - static
재정의한 타입 메서드들은 부모 클래스의 타입 메서드와 다르게 동작하고. 재정의하지 않은 메서드는 부모 클래스와 동일한 기능을 한다.
타입 정의 시 프로퍼티의 기본값을 할당해두면 인스턴스가 초기화 될 때 초기값으로 가지게 된다.
class Person {
var name: String = "unknown"
var age: Int = 0
var nickName: String = "nick"
}
let jane: Person = Person()
jane.name = "jane"
jame.age = 30
jane.nickName = "j"
인스턴스 초기화 후 생성된 인스턴스의 프로퍼티를 각각 변경하여 원하는 값을 할당할 수 있다.
class PersonA {
var name: String
var age: Int
var nickName: String
init(name: String, age: Int, nickName: Stirng) {
self.name = name
self.age = age
self.nickName = nickName
}
}
let jane: PersonA = PersonA(name: "jane", age: 30, nickName: "j")
class PersonB {
var name: String
var age: Int
var nickName: String?
init(name: String, age: Int, nickName: Stirng) {
self.name = name
self.age = age
self.nickName = nickName
}
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let jane: PersonB = PersonB(name: "jane", age: 30, nickName: "j")
let hana: PersonB = PersonB(name: "hana", age: 10)
convenience init(name: String, age: Int, nickName: Stirng) {
self.init(name: name, age: age)
self.nickName = nickName
}
class Pet{
var name: String
var owner: PersonB!
init(name: String) {
self.name = name
}
func goOut(){
print("\(name)이 \(owner.name)과 함께 산책을 갑니다.")
}
}
let puppy: Pet = Pet(name: "happy")
puppy.goOut() // owner가 정의되지 않아 에러 ⚠️
puppy.owner = jane
puppy.goOut() // happy거 jane과 함께 산책을 갑니다.
암시적 추출 옵셔널 [ ! ] 은 인스턴스가 생성될 때 초기값이 필요하진 않거나 할당할 수 없지만, 인스턴스 사용 시엔 반드시 필요한 경우에 사용된다.
이니셜라이저를 실패하면 nil을 반환하게 되므로 실패 가능한 이니셜라이저로 init?
를 사용할 수 있다.
class PersonC {
var name: String
var age: Int
var nickName: String?
init?(name: String, age: Int) {
if name.characters.count == 0{
return nil
}
self.name = name
self.age = age
}
}
let jane: PersonC? = PersonC(name: "jane", age: 30)
let hana: PersonC? = PersonC(name: "", age: 10) // nil
옵셔널 타입의 이니셜라이저를 사용하면 인스턴스 역시 옵셔널 타입으로 선언해야 한다.
인스턴스가 해제되는 시점에 동작을 구현할 수 있다.
class PetOwner{
var name: String
var petName: Pet
var child: PersonC
init(name: String, pet: String, child: String){
self.name = name
self.petName = pet
self.child = child
}
deinit{
print("\(name)이 \(child)에게 \(pet)을 인도합니다.)
self.pet.owner = child
}
}
let jane: PetOwner = PetOwner(name: "jane", pet: "happy", child: "hana")
jane = nil // jane 인스턴스가 메모리에서 해제된다
// jane이 hana에게 happy를 인도합니다.
- 직접 호출 불가능
- 클래스 타입에만 구현 가능
[ 참고자료 ][Swift - Initialization](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html)
Swift - Deinitialization