Skip to content

Latest commit

Β 

History

History
313 lines (237 loc) Β· 10.3 KB

Initialization-2.md

File metadata and controls

313 lines (237 loc) Β· 10.3 KB

Initialization - 2

Initializer Inheritance and Overriding

Automatic Initializer Inheritance

ν•˜μœ„ ν΄λž˜μŠ€λŠ” 일반적으둜 μƒμœ„ 클래슀의 μƒμ„±μžλ₯Ό μƒμ†ν•˜μ§€ μ•ŠλŠ”λ‹€.

κ·ΈλŸ¬λ‚˜, νŠΉμ • μ‘°κ±΄μ—μ„œλŠ” μžλ™μœΌλ‘œ μƒμ†λœλ‹€.

Rule 1

ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ 지정 μƒμ„±μžλ₯Ό μ •μ˜ν•˜μ§€ μ•ŠλŠ” 경우, μƒμœ„ 클래슀의 지정 μƒμ„±μžλ₯Ό μžλ™μœΌλ‘œ μƒμ†ν•œλ‹€.

Rule 2

ν•˜μœ„ ν΄λž˜μŠ€κ°€ Rule 1에 λ”°λ₯΄κ±°λ‚˜ ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ μƒμœ„ 클래슀의 λͺ¨λ“  지정 μƒμ„±μžλ₯Ό κ΅¬ν˜„ν•˜λ©΄ μƒμœ„ 클래슀의 κ°„νŽΈ μƒμ„±μžλ₯Ό μžλ™μœΌλ‘œ μƒμ†ν•œλ‹€.

β†’ 이 κ·œμΉ™λ“€μ€ ν•˜μœ„ ν΄λž˜μŠ€μ— κ°„νŽΈ μƒμ„±μžλ₯Ό 좔가해도 μ μš©λœλ‹€.

Designated and Convenience Initializers in Action

μœ„μ˜ μ„€λͺ… μ˜ˆμ‹œ

class Food {
    var name: String
    init(name: String) {
        self.name = name
    }
    convenience init() {
        self.init(name: "[Unnamed]")
    }
}

let namedMeat = Food(name: "Bacon")
// namedMeat's name is "Bacon"

let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]"

Untitled

  • κ°„νŽΈ μƒμ„±μžκ°€ 지정 μƒμ •μžλ₯Ό delegate across
class RecipeIngredient: Food {
    var quantity: Int
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    override convenience init(name: String) {
        self.init(name: name, quantity: 1)
    }
}

let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)

Untitled

  • 지정 μƒμ„±μžκ°€ Safety Check 1을 만쑱

    πŸ’‘ Safety check 1: μƒμœ„ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜κΈ°μ „μ— ν•΄λ‹Ή 클래슀의 λͺ¨λ“  ν”„λ‘œνΌν‹°κ°€ μ΄ˆκΈ°ν™”λ˜μ–΄μ•Ό 함
  • κ°„νŽΈ μƒμ„±μžμ˜ λ§€κ°œλ³€μˆ˜κ°€ μƒμœ„ 클래슀의 지정 μƒμ„±μžμ™€ λ˜‘κ°™κΈ° λ•Œλ¬Έμ— override둜 μž‘μ„±

  • κ°„νŽΈ μƒμ„±μžκ°€ 지정 μƒμ„±μžλ₯Ό delegate across

  • μƒμœ„ 클래슀의 지정 μƒμ„±μžλ₯Ό λͺ¨λ‘ κ΅¬ν˜„ν–ˆκΈ° λ•Œλ¬Έμ—, μƒμœ„ 클래슀의 κ°„νŽΈ μƒμ„±μžλ₯Ό μžλ™μœΌλ‘œ 상속

    • 이 κ°„νŽΈ μƒμ„±μžλŠ” Food 버전과 λ™μΌν•˜κ²Œ κΈ°λŠ₯ν•˜μ§€λ§Œ, ν•˜μœ„ 클래슀의 init(name)에 delegate across
class ShoppingListItem: RecipeIngredient {
    var purchased = false
    var description: String {
        var output = "\(quantity) x \(name)"
        output += purchased ? " βœ”" : " ✘"
        return output
    }
}

var breakfastList = [
    ShoppingListItem(),
    ShoppingListItem(name: "Bacon"),
    ShoppingListItem(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
    print(item.description)
}
// 1 x Orange juice βœ”
// 1 x Bacon ✘
// 6 x Eggs ✘

Untitled

  • ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ 지정 클래슀λ₯Ό μ§€μ •ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ— μƒμœ„ 클래슀의 지정 μƒμ„±μžμ™€ κ°„νŽΈ μƒμ„±μžλ₯Ό λͺ¨λ‘ μžλ™μœΌλ‘œ 상속

Failable Initializers

  • μ΄ˆκΈ°ν™”κ°€ μ‹€νŒ¨ν•  수 μžˆμ„ λ•Œ μ‚¬μš©ν•˜λ©΄ μœ μš©ν•˜λ‹€.
  • init? ν˜•μ‹μœΌλ‘œ μ‚¬μš©
  • failable μƒμ„±μžμ™€ non-failable μƒμ„±μžμ˜ νŒ¨λŸ¬λ―Έν„°μ™€ 이름이 같을 수 μ—†λ‹€.
  • failable μƒμ„±μžλŠ” μ΄ˆκΈ°ν™”ν•˜λŠ” νƒ€μž…μ— optional valueλ₯Ό μƒμ„±ν•œλ‹€.
  • μ‹€νŒ¨κ°€ μ˜ˆμƒλ˜λŠ” 지점에 return nil λ₯Ό μ‚¬μš©ν•œλ‹€.
    • μƒμ„±μžλŠ” 값을 λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ”λ‹€. μ‹€νŒ¨λ₯Ό λ‚˜νƒ€λ‚΄κΈ° μœ„ν•΄ nil을 μ‚¬μš©ν•˜μ§€λ§Œ, μ΄ˆκΈ°ν™”κ°€ μ„±κ³΅ν–ˆμ„ λ•Œ return ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€.

numeric type conversions μ˜ˆμ‹œ

let wholeNumber: Double = 12345.0
let pi = 3.14159

if let valueMaintained = Int(exactly: wholeNumber) {
    print("\(wholeNumber) conversion to Int maintains value of \(valueMaintained)")
}
// Prints "12345.0 conversion to Int maintains value of 12345"

let valueChanged = Int(exactly: pi)
// valueChanged is of type Int?, not Int

if valueChanged == nil {
    print("\(pi) conversion to Int doesn't maintain value")
}
// Prints "3.14159 conversion to Int doesn't maintain value"

Failable Initializers for Enumerations

  • enum으둜 μ‚¬μš©ν•  λ•Œ ν™œμš© κ°€λŠ₯
  • μ—΄κ±° λͺ©λ‘μ— 없을 경우 μ΄ˆκΈ°ν™” μ‹€νŒ¨ (enum nil λ°˜ν™˜)

Failable Initializers for Enumerations with Raw Values

  • raw value둜 μ΄ˆκΈ°ν™”ν•˜λŠ” enum은 μžλ™μœΌλ‘œ failable μƒμ„±μžλ₯Ό μˆ˜μ‹ ν•œλ‹€.
  • 일치 값이 μ—†μœΌλ©΄ μ΄ˆκΈ°ν™” μ‹€νŒ¨λ₯Ό 트리거

Propagation of Initialization Failure

  • failable μƒμ„±μž(클래슀, 슀트럭쳐, μ΄λ„˜ 포함)λŠ” λ‹€λ₯Έ failable μƒμ„±μžμ—κ²Œ delegate across κ°€λŠ₯
  • ν•˜μœ„ 클래슀의 failable μƒμ„±μžλŠ” μƒμœ„ 클래슀의 failable μƒμ„±μžμ—κ²Œ delegate up κ°€λŠ₯

β†’ μ–΄λ–€ κ²½μš°λ“  μ΄ˆκΈ°ν™”κ°€ μ‹€νŒ¨ν•˜λ©΄ μ΄ˆκΈ°ν™” ν”„λ‘œμ„ΈμŠ€ 전체가 μ¦‰μ‹œ μ‹€νŒ¨ν•˜κ³  더 μ΄μƒμ˜ μ΄ˆκΈ°ν™” μ½”λ“œκ°€ μ§„ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€.

failable μƒμ„±μžλŠ” non-failable μƒμ„±μžμ—κ²Œ delegate κ°€λŠ₯ non-failableν•œ κΈ°μ‘΄ μ΄ˆκΈ°ν™” ν”„λ‘œμ„ΈμŠ€μ— 잠재적인 μ‹€νŒ¨ μƒνƒœλ₯Ό μΆ”κ°€ν•΄μ•Ό ν•˜λŠ” 경우 μ‚¬μš©

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)
    }
}
  • CartItem의 μ΄ˆκΈ°ν™” μ‹€ν–‰ μ‹œ λ‘˜ 쀑 ν•˜λ‚˜λΌλ„ μ΄ˆκΈ°ν™”λ₯Ό μ‹€νŒ¨ν•˜λ©΄ 전체 μ΄ˆκΈ°ν™” ν”„λ‘œμ„ΈμŠ€ μ¦‰μ‹œ μ‹€νŒ¨

Overriding a Failable Initializer

  • μƒμœ„ 클래슀의 failable μƒμ„±μžλ₯Ό ν•˜μœ„ ν΄λž˜μŠ€κ°€ override κ°€λŠ₯
    • μƒμœ„ 클래슀의 failable μƒμ„±μžλ₯Ό ν•˜μœ„ ν΄λž˜μŠ€κ°€ non-failable μƒμ„±μžλ‘œ override κ°€λŠ₯

      β†’ 이λ₯Ό 톡해, μƒμœ„ 클래슀의 μ΄ˆκΈ°ν™”κ°€ μ‹€νŒ¨ν•΄λ„ μ‹€νŒ¨ν•  수 μ—†λŠ” ν•˜μœ„ 클래슀 μƒμ„±μžλ₯Ό μ •μ˜ν•  수 μžˆλ‹€.

      • 이 경우λ₯Ό 만쑱 μ‹œν‚¬ μœ μΌν•œ 방법은 μƒμœ„ 클래슀 failable μƒμ„±μžλ₯Ό κ°•μ œλ‘œ unwrapν•˜λŠ” 것이닀.
    • μœ„μ˜ λ‚΄μš©μ€ κ°€λŠ₯ν•˜μ§€λ§Œ λ°˜λŒ€μ˜ 경우(non-failable μƒμ„±μžλ₯Ό failable μƒμ„±μžλ‘œ overrideν•˜λŠ” 것)은 λΆˆκ°€λŠ₯

class Document {
    var name: String?
    // this initializer creates a document with a nil name value
    init() {}
    // this initializer creates a document with a nonempty name value
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}

class AutomaticallyNamedDocument: Document {
    override init() {
        super.init()
        self.name = "[Untitled]"
    }
    override init(name: String) {
        super.init()
        if name.isEmpty {
            self.name = "[Untitled]"
        } else {
            self.name = name
        }
    }
}
  • μƒμœ„ 클래슀의 지정 μƒμ„±μžλ₯Ό λͺ¨λ‘ override
  • μƒμœ„ 클래슀의 failable μƒμ„±μžλ₯Ό non-failable μƒμ„±μžλ‘œ override
class UntitledDocument: Document {
    override init() {
        super.init(name: "[Untitled]")!
    }
}
  • κ°•μ œ unwrapping으둜 non-failable μƒμ„±μžλ‘œ 상속

  • μƒμœ„ 클래슀의 init(name:) μƒμ„±μžμ— 빈 λ¬Έμžμ—΄μ΄ λ“€μ–΄κ°ˆ 경우, λŸ°νƒ€μž„μ—λŸ¬ λ°œμƒ

    β†’ 항상 μ‹€νŒ¨ν•˜μ§€ μ•Šλ„λ‘ λ§€κ°œλ³€μˆ˜λ₯Ό μ‚¬μš©ν•΄μ€˜μ•Ό ν•œλ‹€.

The init! Failable Initializer

  • Optional이 μ•„λ‹Œ failable μƒμ„±μžλ₯Ό λ§Œλ“€κ³  싢을 λ•Œ μ‚¬μš©
  • init! ν˜•μ‹
  • init? β†’ init!, init! β†’ init? : delegate, override κ°€λŠ₯
  • init β†’ init! : delegateν•  수 μžˆμ§€λ§Œ, init!이 μ‹€νŒ¨ν•œλ‹€λ©΄ assertion을 trigger ν•œλ‹€.

Required Initializers

  • μ–΄λ–€ 클래슀의 λͺ¨λ“  ν•˜μœ„ ν΄λž˜μŠ€κ°€ μƒμ„±μžλ₯Ό ν•„μˆ˜μ μœΌλ‘œ κ΅¬ν˜„ν•˜κ²Œ ν•˜κ³  싢을 λ•Œ μ‚¬μš©

  • required ν‚€μ›Œλ“œ μ‚¬μš©

    • μ—°μ†μ μœΌλ‘œ λ°œμƒν•œ ν•˜μœ„ ν΄λž˜μŠ€μ— 이 μƒμ„±μžλ₯Ό ν•„μˆ˜λ‘œ κ΅¬ν˜„ν•΄μ•Ό 함을 μ•Œλ¦¬κΈ° μœ„ν•΄ required ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.
  • override ν‚€μ›Œλ“œλŠ” μ‚¬μš© X

  • μƒμ†λœ μƒμ„±μžλ₯Ό μ‚¬μš©ν•˜μ—¬ μΆ©μ‘±ν•  수 있으면, ν•„μˆ˜ μƒμ„±μžλ₯Ό λͺ…μ‹œμ μœΌλ‘œ κ΅¬ν˜„ν•  ν•„μš” μ—†λ‹€.

    β†’ μΆ©μ‘±: λͺ¨λ“  μ„ μ–Έν•œ ν”„λ‘œνΌν‹°λ₯Ό μ΄ˆκΈ°ν™”ν•˜λŠ” 것

protocol JSONInitializable { // Use Encoders, but just for example
    init(fromJSON: String)
}

class Foo: JSONInitializable  {
    let x: Int

    // "required" is necessary because this init is required for the 
    // conformance to JSONInitializable
    required init(fromJSON json: String) {
        //...
        x = 123 //some value from the JSON
    }
}

class Baz: Foo {
    // `init(fromJSON json: String)` can be inherited,
    // so it's implicitly defined for Baz, as well as Foo.
}

class Bar: Foo {
    // The presence of this uninitialized constant `y` requires an
    // a value in the declaration, or an initializer that sets it
    let y: Int

    // Since we didn't specify a value for `y` in its declaration,
    // this initializer must be explicitly specified so as to initialize `y`.
    // Doing so blocks the inheritance of `init(fromJSON json: String)` from
    // the super class, and requires us to define it ourselves,
    // in order to preserve conformance to `JSONInitializable`
    required init(fromJSON json: String) {
        //...
        y = 0
        super.init(fromJSON: json)
    }
}

Setting a Default Property Value with a Closure or Function

  • μ €μž₯ ν”„λ‘œνΌν‹°μ˜ default 값에 섀정이 ν•„μš”ν•œ 경우, ν΄λ‘œμ € λ˜λŠ” μ „μ—­ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.
class SomeClass {
    let someProperty: SomeType = {
        // create a default value for someProperty inside this closure
        // someValue must be of the same type as SomeType
        return someValue
    }()
}
  • ()λŠ” ν΄λ‘œμ €λ₯Ό μ¦‰μ‹œ μ‹€ν–‰ν•˜κ²Œ ν•˜λ©°, 없을 경우 ν΄λ‘œμ € 자체λ₯Ό ν”„λ‘œνΌν‹°μ— ν• λ‹Ήν•œλ‹€.
  • ν΄λ‘œμ €κ°€ μ‹€ν–‰λ˜λŠ” μ‹œμ μ— λ‚˜λ¨Έμ§€ μΈμŠ€ν„΄μŠ€λŠ” 아직 μ΄ˆκΈ°ν™”κ°€ λ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— μ ‘κ·Ό ν•  수 μ—†λ‹€.
    • self와 μΈμŠ€ν„΄μŠ€ λ©”μ„œλ“œ 호좜 λΆˆκ°€λŠ₯

좜처

https://docs.swift.org/swift-book/LanguageGuide/Initialization.html

https://stackoverflow.com/questions/44975479/what-does-this-mean-you-do-not-have-to-provide-an-explicit-implementation-of-a