본문 바로가기

스피드 문법정리

18. Initializer and Deinitializer

Initializers

init(parameters) {
    initialization
}
TypeName(parameters)

새로운 인스턴스를 생성하는 것은 초기화하고 부름,  인스턴스의 초기화를 담당하는 것은 Initializer라고 부름, 초기화의 목적은 모든 속성을 기본값으로 초기화해서 인스턴스를 기본상태로 만드는 것, 인스턴스가 정상적으로 초기화되었다는것은 모든속성이 기본값을 가지고 있다는 뜻

속성이 항상 동일한 값으로 초기화 된다면 선언과 동시에 기본값 저장, 파라미터를 활용하여 초기화를 저장할 때는 Initializer를 사용하여 저장

class Position {
    var x = 0.0 // 선언과 동시에 기본값 저장
    var y : Double
    var z : Double?
    init() {
        y = 0.0 // Initializer를 사용하여 저장
    }
}

Default Initializer

만약 모든 속성이 기본값을 가지고 있고 직접 Initializer를 구현하지 않는다면 Default Initializer 자동 제공, 인스턴스를 생성하기 위해서는 Initializer 생성해야 하지만 모든속성이 기본값을 가지고 있다면 컴파일러가 자동으로 Default Initializer 생성 

class Position {
    var x = 0.0
    var y : 0.0
    var z : Double = nil
}
let p = Position()

Memberwise Initializer

구조체에서 Initializer를 구현하지 않았을 때 자동으로 제공 하지만 Initializer를 구조체 내부에서 사용한다면 제공되지 않음, 파라미터를 통해 모든 속성을 초기화

struct SizeValue {
    var width = 0.0
    var height = 0.0
}
let s = SizeValue()
SizeValue(width : 1.2, height : 3.4)

Class Initializer

Designated Initializer

클래스가 가진 모든 속성을 초기화, 구현가능한 갯수는 무제한이나 대부분 1개를 사용, Default Initializer를 사용하거나, SuperClass로 부터 Designated Initializer를 상속했다면 Designated Initializer를 직접 구현할 필요는 없음 하지만 나머지의 경우 최소한 하나의 Designated Initializer가 필요

init(parameters) {
    initialization
}
class Position {
    var x : Double
    var y : Double
    
    init(x : Double, y : Double) {
        self.x = x
        self.y = y
    }
}

Convenience Initializer

다양한 초기화 방법을 구현하기 위한 유틸리티 성격의 Initializer, Designated Initializer와 달리 반드시 모든 속성을 초기화하지는 않음, 필요한 속성만 초기화 한 다음 class 에 있는 다른 Initializer를 호출하여 나머지 초기화를 완료하도록 구현

convenience init(parameters) {
    initialization
}

 

class Position {
    var x : Double
    var y : Double
    
    init(x : Double, y : Double) {
        self.x = x
        self.y = y
    }
    convenience init(x : Double) {
        self.inti(x : x, y : 0.0)
    }
}

Initializer Inheritance

superclass 생성된 Initializer는 기본적으로 subclass에 상속되지 않음

2가지 규칙에 따라 Initializer를 상속

1. subclass의 모든 속성이 기본값으로 초기화 되어있고 Designated Initializer를 직접 구현하지 않았다면 super class에 있는 모든 Designated Initializer가 상속됨

2. subclass가 모든 Designated Initializer를 상속 받았거나 overriding 했다면 모든 convenience Initializer가 상속됨

class Figure {
    var name : String
    
    init(name : String) {
        self.name = name
    }
    func draw() {
        print("draw\(name)")
    }
    convenience init() {
        self.init(name : "unknown")
    }
}

class Rectangle : Figure {
    var width : Double = 0.0
    var height : Dobuel = 0.0
    
    init(name : String, width : Double, height : Double) {
        self.width = width
        self.heigth = height
        super.init(name : name) // 현재 class에 있는 속성을 초기화한 다음에 상위구현 호출
    }
    
    override init(name : String) {
        width = 0
        height = 0
        super.init(name : name)
    }
    
    convenience init() {
        self.init(name : "unknown")
    }
}

Required Initializer

특정 Initializer 직접 구현하도록 강제하고 싶을 때 사용

모든 속성이 기본값을 가지고 있고 Initializer를 직접 구현하지 않을 경우 subclass로 Initializer가 상속됨으로 required Initializer는 직접 구현하지 않아도 상관없음

superclass와 동일한 Initializer를 subclass에서 구현하는 것은 overriding이라고 함 하지만 subclass 에서 required Initializer를 구현 할 경우 superclass와 완전히 동일한 형태로 구현 -> Rectangle을 상속하는 다른 subclass들이 다시 동일한 Initializer를 구현하도록 강제하기 위해서 임

required init(parameters) {
    initalization
}
class Figure {
    var name : String
    
    required init(name : String) {
        self.name = name
    }
    
    func draw() {
        print(draw\(name)")
    }
}

class Rectangle : Figure {
    var width = 0.0
    var height = 0.0
    
    init() {
        width = 0.0
        height = 0.0
        super.init(name : unknown")
    }
    
    required init(name : String) {
        width = 0.0
        height = 0.0
        super.init(name : name)
    }
}

Initializer Delegation

초기화 코드에서 중복을 최대한 제거하고 모든 속성을 효율적으로 초기화하기위해 사용

다른 Initializer를 호출하는 것을 Initializer Delegation이라고 함, 단순히 다른 Initializer를 호출한다고 해서 

Initializer Delegation이 되는 것은 아니고 모든 Initializer가 실행된 다음에 전체 속성이 초기화 되어야 함

Value Type

struct Size {
    var width : Double
    var height : Double
   
    init(w : Double, h : Double) {
        width = w
        height = h
    }
   
    init(value : Double) {
        self.init(w : value, h : value)
        //width = value
        //height = value
    }
}

Class

1. Designated Initializer는 반드시 supclass의 Designated Initializer를 호출해야함 (Delegate Up)

2. convenience Initializer는 동일한 class에 있는 다른 Initializer를호출 해야함 (Delegate Across)

3. convenience Initializer를 호출했을 때 최종적으로 동일한 class에 있는 Designated Initializer가 호출되어야함

class Figure {
    let name : String
    
    init(name : String) {
        self. name = name
    }
    convenience init() {
   	    self.init(name : "unknown") // 앞에 있는 Designated Initializer 호출 중 (Delegate Across)
    }
}

class Rectangle : Figure {
    var width = 0.0
    var height = 0.0
    
    init(n : String, w : Double, h : Double) { // 모든 속성을 초기화한 다음에 마지막 상위 구현 호출 (Delegate Up)
        width = w
        height = h
        super.init(name : n)
    }
    
    convenience init(value : Double) {
        self.init(n : "rect", w : value, h : value)
    }
}

class Square : Rectangle { // 속성, Designated Initializer 미구현 -> Rectangle에 있는 Designated Initializer 상속
    convenience init(value : Double) { // 여기서 호출된 Initializer는 상속된 Initializer
        self.init(n : "rect", w : value, h : value) //convenience Initializer는 어떤 경우에도 Delegate Up 불가능
    }                                               // super. 불가능   
    
    convenience init() {
        self.init(value : 0.0)
    }
}

square 클래스의 Initializer 호출되면 인스턴스를 저장할 메모리 공간이 형성(메모리가 초기화된 상황은 아님) -> convenience init() 호출 -> 

Rectangle에서 상속 받은 Designated Initializer가 호출 -> 여기까지 Delegate Across -> Designated Initializer는 Delegate Up 이라서 Rectangle에 있는 Designated Initializer가 실행 후 속성을 초기화한 후 다시 상위구현 호출->

Figure클래스에 있는 Designated Initializer가  호출 -> 상속 계층에 있는 모든 속성이 초기화됨 -> 반대로 내려가며 부가적인 초기화가 실행되면 완료되면 인스턴스 초기화가 완료됨

 

 

 

Failable Initializer

Nonfailable Initializer의 경우 초기화의 실패를 허용하지 않으나 Failable Initializer는 초기화의 실패를 허용하면 실패할경우 nil을 반환함

init?(parameters) {
    initialization
}
init!(parameters) {
    initialization
}
struct Position {
    let x : Double
    let y : Double
    
    init?(x : Double, y : Double) {
        guard x >= 0.0, y >=0.0 else { return nil }
        self.x = x
        self.y = y
    }
    init!(value : Double) {
        guard value >= 0.0 else { return nil }
        self.x = value
        self.y = value
    }
    
}
var a = Position(x : 12, y : 34)
a = Position(x : -12, y : 0) // nil

var b = Position(value :12)
b = Position(value : -12) // nil

Deinitializer

인스턴스가 메모리에서 제거되기전에 부가적인 정리작업을 구현하기 위해 사용, class 전용, 1개로 제한

deinit {
    Deinitialization
}
class Size {
    var width = 0.0
    var height = 0.0
}

class Position {
    var x = 0.0
    var y = 0.0
}

class Rect {
    var origin = Position()
    var size = Size()
    
    deinit {
        print("deinit \(self)")
    }
}

var r Rect? = Rect()
r nil 

'스피드 문법정리' 카테고리의 다른 글

11. String and Character  (0) 2020.06.24
20. Protocol  (0) 2020.06.23
17. Inheritance and Polymorphism  (0) 2020.06.19
16. Method and Subscript  (0) 2020.06.19
15. Property  (0) 2020.06.18