iyOmSd/Title: iOS Think🤔

[iOS] initialization 생성자

냄수 2020. 8. 13. 23:32
반응형

스위프트에는 여러종류의 init이 있다는거 알고계셧나요?

 

객체를 생성할 때 제공되는 함수를 말하구요

생성자를 통해서 객체를 생성할 때 원하는 값을 설정해서 만들 수가 있어요

 

 

  • designated init 
  • custom init
  • default init
  • convenience init
  • required init
  • failable init
  • memberwise init

이제부터 하나하나 위에서 언급한 init을 알아볼게요

 

 

 

designated init

지정된 초기화라는 뜻이에요

보통 지금까지 많이 봤던 init이에요

모든 class는 적어도 1개이상 가지고 있어야해요 선언되지않으면 default init함수가 제공되요

하지만 이때 저장프로퍼티가 있는데 초기화가 안되어있다면 불가능해요

class를 만들때 변수초기화를 꼭 해줘야하잖아요?? :)

가장 기본적인 역할을 하구요

저장프로퍼티 초기화를 책임지고 있어요

custom init이기도하죠

// case1
class A {
    init() {  // <<- designated init
    ...
    }
}
A() // 객체생성

// case2
class A {}
A() // default init함수적용

// case3
class A {
    let a: String  // 초기화 에러
}
A() // 불가능

 

 

custom init

구현한 init이에요

객체를 만들 때 받아온 값으로 초기값을 정해주는 거에요 

designated init도 custom init에 속하죠

init을 새로 만들어 줄 수 있으니까요

(custom init과 designated모두 보통 init들이라고 생각하면되요)

 

 

default init

아무값도 받지않고 임의의 디폴트값으로 설정하는거에요

값을 class나 struct내에서 정해주는거에요

class A {
    let a = 123  // default init
}

class A {
    let a: Int
    
    init() {
        a = 123  // default init
    }
}

 

 

 

convenience init

보조 이니셜라이저구요

다른 init에 의존적인 init이에요

중요한 기능은 다른 init에게 맡기고 자신은 특정한 일만 수행하구요

반드시 self.init을 통해 다른 init을 호출해야해요

따라서 designated init이 하나는 있어야해요

class A {
    let aa: Int
    
    init (a: Int) {
        aa = a
    }
    
    init (a: Int, b: Int) {
        aa = a
        print(b)
    }
    
    convenience init(c: Int) {
        self.init(a: 3, b: c)
    }
}

여기서 그러면 

init(a: Int)

convenience init(c: Int)의 차이는 뭘까요..??

생성할때 

객체를 생성하는 방식이 같네요!?!?

 

그러면... 코드가 다른거아닌가요..??!

 

위의 코드는 다르게 구현했기 때문에 다르지만

만약 init(a: Int)에서 init(c: Int)와 같은 코드를 구현하게 된다면

init(c: Int)는 어디에 쓰는걸까요...??

 

제 생각에는 그 class타입에만 해당되는 생성자라고 생각해요

상속을 받아도 그 init은 해당이 되지않는거죠

상속받은 class의 생성자에는 init(c: Int)가 없는게 보이시나요??

또한 convenience initstruct(구조체) 에서는 사용할 수 없는 이니셜라이저에요!!

그렇기 때문에 해당 class에서만 사용하는 생성자임을 명시하는게 차이인것 같아요

 

더 찾아보니

 

이러한 설명이 공식문서에 설명이 잘되어있는데요( 제 가정이 다 틀리진 않은것같아요.. ㅎ )

 

한글로 번역된 문서에요

xho95.github.io/xcode/swift/grammar/initialization/2016/01/23/Initialization.html

 

Swift 5.3: Initialization (초기화)

Apple 에서 공개한 The Swift Programming Language (Swift 5.3) 책의 Initialization 부분을 번역하고, 설명이 필요한 부분은 주석을 달아서 정리한 글입니다. 현재 번역이 진행 중인데, 2020-06-22 에 Swift 5.3 이 발표

xho95.github.io

 

이러한 규칙을 적용해야해요

간단하게 요약하자면

Convenience는 의존적인 생성자고 클래스내의 designated을 호출 해줘야해요 

그래서 수평적인 호출을 하고

Designated는 상위계층이 있다면 상위init을 불러줘야하므로

수직적인 호출을 한다는 내용이에요

 

 

 

required init

자신을 상속하는 subclass들이 모두 따라야하는 필수 init이에요

상속받는 자식class에 init을 따로 구현해주지 않는다면 부모것을 쓰기 때문에 아무런 문제가 없지만

init을 구현한다면 required init은 꼭 구현해줘야 해요

init을 구현한다면 이렇게 에러를 볼수잇죠...

 

class A {
    init() {
        
    }
    
    required init(a: Int) {
        print(a)
    }
}

class B: A {
    override init() {
        super.init()
    }
    
    required init(a: Int) {
        super.init()
        fatalError("init(a:) has not been implemented")
    }
}

 

 

failable init

특정조건에서는 생성이 안되도록 정의해주는거에요

init옆에 ?를 붙여서 init?() 형태로 사용해요

class A {
    init?(a: Int) {
        if a == 0 {
            return nil
        }
        print(a)
    }
}

let a1 = A(a: 0)
let a2 = A(a: 1)

print(a1)  // nil
print(a2)  // Optional(A)

 

 

memberwise init

struct에만 존재하는 이니셜라이저에요

자동으로 init이 제공되는 것을 말해요

 

객체가 생성될때 필요한 인자들을 자동으로 요구해줘요

 

우선 첫번째로는 아래와 같이 프로퍼티가 있는경우

struct는 init을 안 만들어도 에러가없지만

class는 init을 만들어 줘야해요

 

구조체인 B는 init을 안 구현해줘도

이렇게 자동으로 만들어줘요

이 기능을 memberwise init이라고 해요

 

 

반응형