iOS/Swift

Swift) 초기화(Initializers) 이해하기 (3/6) - Initializer Delegation

소들이 2022. 9. 26. 22:15

 

 

안녕하세요 :) 소들입니당

이번 포스팅은 초기화(Initializers) 이해하기 3편~~!!!!

Initializer Delegation에 대해 이해해보려고 합니당

초기화가 처음에 공부하면 어려운 만큼 Delegation을 이해하기 어려울 수도 있는데...!!!

이전 포스팅을 완벽하게 이해 했다면 정말 별 거 없습니당 ㅎ_ㅎ

모든 포스팅은 편의 말투로 합니다~!!

 

 

 

 

1. Initializer Delegation

 

Initializer Delegation이란,

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

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

값 형식(구조체)와 참조(클래스) 형식이 다릅니다

 

을 말 한답니다~

응 이론은 갱장히 쉬워~~

 

먼저 값 형식과 참조 형식이 다르다고 했는데,

이는 바로 "상속"의 여부가 갈리기 때문임!!

 

먼저, 값 타입(구조체) 형식부터 보겠음!!

예제로 공부해보쟈 :)

 

 

 

1-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
    }
}
 

 

이렇게 작성해도 문제는 아님!

근데 위 두개의 Initializer의 경우,

모든 프로퍼티 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
    }
}
 

 

 

이렇게 모든 초기화에 손을 대어, 해당 프로퍼티의 값을 바꿔주어야 한단 말임!!

이는 Initializer Delegation을 따르고 있지 않는 것

그럼 이는 Initializer 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를 통해서 유지보수가 쉬워진 것

이것이 바로 구조체에서의 Initializer Delegation임ㅎㅎ

별 거 없음!!

 

 

 

1-2. 참조 타입에서의  Initializer Delegation

 

참조 타입에서의 Initializer Delegation은 구조체보단 살짝 복잡함

이전에 우리가 공부 했단 내용 몇 가지만 복기하고 가겠음!!

 

클래스의 생성자는 총 두 가지의 종류가 있다!

 

Designated Initializers

우리가 아무렇지 않게 init 하고 썼던 초기화로

init 함수가 끝나기 전엔 모든 프로퍼티의 값이 초기화 되어 있어야 한다!

(모든 프로퍼티가 기본 값을 갖거나 옵셔널 타입의 변수로 선언된 경우엔 작성하지 않아도 됨!)

서브 클래스인 경우, super 클래스의 init 메서드를 반드시 호출 해줘야 한다!

 

 

Convenience Initializers

Designated Initializers의 초기화를 "보조"해주는 역할의 초기화다!

Designated Initializers의 파라미터 중 일부를 기본값으로 설정해서 호출할 수 있다!

이 Convenience Initializers는 반드시 다른 초기화 메서드를 호출시켜주어야 하는데,

이때 다른 초기화 메서드란, 

Convenience / Designated든 상관 없이 같은 클래스 내에 있는 초기화 메서드기만 하면 된다

다만!!!!!! 최종적으론 반드시 같은 클래스(계층) 내에 있는 Designated Initializers가 호출되어야 한다!

 

 

위 개념만 기억한다면 정말 별 거 없음

클래스의  Initializer Delegation는 다음과 같은 총 3가지 규칙을 따라야 함

 

 

 

1️⃣ Delegate Up

 

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

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

 

 

 

저번에 공부한 내용이라 어렵지 않음 :)

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

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

초기값을 가지지 않았다면 초기화 안 되는데 어쩔거임

 

따라서,

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

 

 

 

2️⃣ Delegate Across (1)

 

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

 

이또한 이전 포스팅에서 자세히 공부 했잖음!?ㅎㅎ

convenience Initializers의 가장 큰 핵심은

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

그것이 convenience든 Designated든!!

 

 

 

3️⃣ Delegate Across (2)

 

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

 

근데 이제 뭐다?

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

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

 

정리하자면,

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

그럼 초기화 안 된 프로퍼티가 있으면 어케?

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

왜냐? Designated Initializers는 모든 프로퍼티를 초기화 시킬테니까!!

 

Convenience init은 지네끼리 호출하고 난리쳐도

결국 마지막엔 Designated로 귀결 된다!! 하하!

 

라고 저번 포스팅에서ㅓ 말했삼

정말 어렵지 않죠!?!?!

 

 

 

 

이렇게 볼 수 있다 :)

 

 

 

 

 

 

 

 

.

.

.

 

저는 처음에 Swift를 딱 공부 할 때

이 망할 Initializer 때문에 정말 머리가 깨지는 줄 알았었어여

처음 접하면 개념이 어렵기도 하구,

네이밍도 어렵고(Designated, Convenienceㅋ) 등등

걍 첨 공부할 때 델리게이션은 뭐 어쩌라고 나중에 공부해라 급

 

최대한 이해하기 쉽게 쓴 것 같은데,

저도 사람이라 혹시 틀린 내용이 있거나 피드백줄 내용은 꼭 댓글 바랍니다!!

도움이 되셨길 바라며 :)