초기화(Initializers) Initializer Delegation - ehrldyd15/Swift_Skills GitHub Wiki

초기화(Initializers) - Initializer Delegation

Initializer Delegation 이란?

생성자에서 또 다른 생성자를 호출하여 초기화 코드의 중복을 최대한 제거하고,

모든 프로퍼티를 효율적으로 초기화 하기위해 사용하는 것이다.

값 형식(구조체)와 참조(클래스) 형식이 다르다는 것이 중요한데 그 이유는 상속의 여부가 갈리기 때문이다.

1. 값 타입에서의 Initializer Delegation

값 타입의 Initializer Delegation는 상속이 없어서 매우 단순하다.

    struct Position {
        var x: Int
        var y: Int
        
        init(xPos: Int, yPos: Int) {
            x = xPos
            y = yPos
        }

        init(pos: Int) {
            x = pos
            y = pos
        }
    }

위 처럼 작성해도 문제가 되지 않지만

모든 프로퍼티 x, y값을 초기화 하는 코드를 두 곳 모두에서 작성하고 있으니, 이는 죽복된 코드이다.

따라서 만약 Initializer에서 y는 무조건 0으로 초기화 하는 것으로 바뀌어야 한다면

    struct Position {
        var x: Int
        var y: Int
        
        init(xPos: Int, yPos: Int) {
            x = xPos
            y = 0
        }

        init(pos: Int) {
            x = pos
            y = 0
        }
    }

이렇게 모든 초기화에 손을 대어, 해당 프로퍼티의 값을 바꿔야 한다.

이것은 nitializer Delegation을 따르고 있지 않는 것이다.

따라서 생성자에서 "또 다른 생성자"를 호출하여 초기화 코드의 중복을 최대한 제거 하려면

    struct Position {
        var x: Int
        var y: Int
        
        init(xPos: Int, yPos: Int) {
            x = xPos
            y = yPos
        }

        init(pos: Int) {
           self.init(xPos: pos, yPos: pos)
        }
    }

위 처럼 작성해 준다.

모든 프로퍼티를 초기화 하는 Initializer를 먼저 하나 만들고,

다른 Initializer가 이 Initializer를 사용하게 만드는 것이다.

이 경우, 초기화 코드의 중복도 제거 할 수 있고, 만약 초기화 코드를 수정할 일이 있다고 하더라도

    struct Position {
        var x: Int
        var y: Int
        
        init(xPos: Int, yPos: Int) {
           x = xPos
           y = 0 // ✅ 수정 및 추가 
        }

        init(pos: Int) {
           self.init(xPos: pos, yPos: pos)
        }
    }

위처럼 모든 프로퍼티를 초기화 하는 Initializer 하나만 수정해도 된다.

Initializer Delegation를 통해서 유지보수가 쉬워진다.

2. 참조 타입에서의 Initializer Delegation

클래스의 Initializer Delegation는 3가지 규칙을 따라야 한다.

1) Delegate Up

Designated Initializer는 반드시 슈퍼 클래스의 Designated Initializer를 호출해야 한다.

(슈퍼 클래스의 Designated Initializer를 호출하는 다른 이니셜라이저를 호출하는 것도 안된다.)

스크린샷 2022-09-29 오전 10 38 44

만약 내 프로퍼티만 모두 초기화 시키는 init 함수를 작성할 경우,

내 부모(슈퍼) 클래스의 프로퍼티 중 만약 기본값이나 옵셔널 타입의 변수가 아니라서

초기값을 가지지 않았다면 초기화가 안 되므로

슈퍼 클래스의 모든 프로퍼티를 초기화 시키는 Designated Initializer를 반드시 호출 해야한다.

2) Delegate Across (1)

Convenience Initializer는 반드시 동일한 계층(클래스)의 initailizer를 호출해야 한다.

convenience Initializers의 가장 큰 핵심은

반드시 같은 클래스(슈퍼 클래스X)에 있는 "다른 초기화"를 또 호출시켜야 한다는 것이다.

3) Delegate Across (2)

Convenience Initializer는 최종적으로 동일한 계층(클래스)의 Designated initialize를 호출해야 한다.

그런데

Convenience Initializers는 Designated Initializers를 "보조"하는 역할이기 때문에

최종적으로는, 같은 클래스 내에 있는 Designated Initializers를 호출 시켜야 한다.

정리하자면,

Convenience Initializers는 "보조" 생성자이기 때문에, 굳이 모든 프로퍼티를 초기화 할 필요가 없다.

어차피 최종적으로는 같은 클래스 내에 있는 Designated Initializers를 호출 시키기 때문에 문제가 없다.

Designated Initializers는 모든 프로퍼티를 초기화 시키기 때문이다.

스크린샷 2022-09-29 오전 11 02 41

위 처럼 정리할 수 있다.

참고 자료

https://babbab2.tistory.com/169?category=828998