서브클래스의 초기자 구현이 편의 초기자인 경우에도 슈퍼클래스의 지정 초기자를 재정의하는 경우엔 항상 override 모디파이어를 작성해야 한다.
class Hoverboard: Vehicle {
var color: String
init(color: String) {
self.color = color
// super.init() implicitly called here
}
override var description: String {
return "\(super.description) in a beautiful \(color)"
}
}
기본적으로 서브클래스는 슈퍼클래스 초기자를 상속받지 않는다.
그러나 특정한 조건 아래에서 자동적으로 상속된다.
이는 많은 일반적인 상황에서는 override 초기자를 작성할 필요가 없다는 뜻이고, 안전할 경우 슈퍼클래스 초기자를 적은 노력으로 상속가능하다는 뜻이다.
서브클래스의 모든 새로운 프로퍼티에 기본값을 제공한다고 할 때 아래 두 규칙이 적용된다:
이러한 규칙들은 서브클래스가 추가적인 편의 초기자를 추가하는 경우에도 적용된다.
서브클래스는 2번 규칙을 준수하는 것의 일부분으로 슈퍼클래스의 지정 초기자를 편의 생성자로 구현할 수 있다.
실패 가능한 초기자와 일반 초기자를 동일한 매개변수 타입과 이름으로 정의할 수 없다.
엄밀히 말하면 초기자는 값을 반환하지 않는다. 그보다는 초기화가 끝날 때까지 self가 완전하고 올바르게 초기화되었는지 확인하는 역할을 한다. 초기화 실패를 트리거하기 위해 nil 반환값을 작성하지만 초기화 성공을 나타내기 위해 return 키워드를 사용하지는 않는다.
struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}
let someCreature = Animal(species: "Giraffe")
// someCreature is of type Animal?, not Animal
if let giraffe = someCreature {
print("An animal was initialized with a species of \(giraffe.species)")
}
// Prints "An animal was initialized with a species of Giraffe"
enum TemperatureUnit {
case kelvin, celsius, fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .kelvin
case "C":
self = .celsius
case "F":
self = .fahrenheit
default:
return nil
}
}
}
let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
// Prints "This is a defined temperature unit, so initialization succeeded."
let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
print("This isn't a defined temperature unit, so initialization failed.")
}
// Prints "This isn't a defined temperature unit, so initialization failed."
enum TemperatureUnit: Character {
case kelvin = "K", celsius = "C", fahrenheit = "F"
}
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
// Prints "This is a defined temperature unit, so initialization succeeded."
let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
print("This isn't a defined temperature unit, so initialization failed.")
}
// Prints "This isn't a defined temperature unit, so initialization failed."
실패 가능한 초기자는 일반 초기자도 위임 가능하다. 실패하지 않는 기존 초기화 프로세스에 잠재적인 실패 상태를 추가해야 하는 경우 이 방법을 사용하면 됨.
class Product {
let name: String
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class CartItem: Product {
let quantity: Int
init?(name: String, quantity: Int) {
if quantity < 1 { return nil }
self.quantity = quantity
super.init(name: name)
}
}
if let twoSocks = CartItem(name: "sock", quantity: 2) {
print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
// Prints "Item: sock, quantity: 2"
if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
} else {
print("Unable to initialize zero shirts")
}
// Prints "Unable to initialize zero shirts"
if let oneUnnamed = CartItem(name: "", quantity: 1) {
print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
} else {
print("Unable to initialize one unnamed product")
}
// Prints "Unable to initialize one unnamed product"
실패 가능한 초기자를 일반 초기자로 오버라이딩 할 수는 있지만 그 반대는 불가능하다.