[iOS] Required Initializers & Failable Initializer

RudinP·2024년 6월 21일
0

Study

목록 보기
231/258

Required Initializer

  • 필수 생성자
//Required Initializer

class Person{
    let name: String
    
    init(name: String) {
        self.name = name
    }
}

class Member: Person {
    var point = 0
}
  • 이러한 상황에서 Person을 상속한 Member 클래스에서도 생성자를 필수로 만들도록 강제하고 싶을 때 required initializer을 사용한다.
required init(name: String) {
        self.name = name
}
  • 다만, 현재 상황에서는 생성자 또한 상속되고 있기 때문에 에러가 발생하진 않는다. 이 때는 직접 구현하지 않아도 된다.
  • 그러나 생성자를 선언하게 된다면 required initializer이 필요하다는 에러가 발생한다.
class Member: Person {
    var point = 0

    init() {
        point = 0
        super.init(name: "unknown")
    }
    
    required init(name: String) {
        point = 0
        super.init(name: name)
    }
}

문법

  • required init을 사용할 때에는 슈퍼클래스의 required init과 완전히 동일한 형태여야 한다. 즉, 매개변수가 같아야 한다.

Failable Initializer

  • 보통은 컴파일 타임에 모든 속성이 초기화된다.
  • 이는 Non-Failable Initializer이라고 한다.
  • 파일에서 데이터를 읽어와 인스턴스를 초기화 하는 경우에는 초기화가 보장되지 않고, 실패 시 런타임 에러로 크래시가 발생할 것이다.
  • 이 때 Failable Initializer을 사용한다면 컴파일에러나 런타임 에러가 발생하지 않고 nil로 초기화된다.
  • 쉽게 말하자면 initializer의 옵셔널 버전이다.
  • 사용하는 이유: 초기화에 실패해도 에러를 발생시키지 않기 위함

문법

  • init?이나 init!을 사용하면 된다.
  • init?: 초기화에 성공했을 때 인스턴스를 옵셔널 형식으로 리턴, 실패 시 nil 리턴
  • init!: 초기화에 성공했을 때 인스턴스를 non-optional 형식으로 리턴. 실패 시 크래시 발생. (비추천)
struct Position {
    let x: Double
    let y: Double
    
    init?(x: Double, y: Double){
        guard x >= 0.0, y >= 0.0 else {
            return nil // 초기화에 실패했다는 의미로 nil을 리턴
        }
        
        self.x = x
        self.y = y
    }
    
    init!(value: Double){
        guard value >= 0.0 else {
            return nil // 초기화에 실패했다는 의미로 nil을 리턴
        }
        
        self.x = value
        self.y = value
    }
}

init?

init!

  • init!에서 크래시가 나지 않는 이유: 인스턴스 리턴 시 옵셔널은 맞는데, IUO타입으로 리턴된다.
  • IUO타입은 값이 자동으로 unwrapping 된다.
  • 형식 추론을 사용한다면 자동으로 unwrapping되지 않는다. 따라서 nil을 리턴한다.
  • 형식 추론을 사용하지 않는다면 크래시가 발생한다.
  • 이는 failable initializer을 사용하는 목적에 맞지 않아 잘 사용되지 않는다.
  • 주로 유닛테스트,프로토타입 코드에서만 제한적으로 사용한다.

구현 규칙

  • 오버로딩 느낌이기 때문에 똑같은 파라미터를 가진 non-failable initializer을 생성하면 에러가 발생한다. 즉, failable과 non-failable을 구분하지 않는다.
  • non-failable initializer에서 failable initializer을 사용할 수 없다.
    • non-failable은 무조건 컴파일 타임에 초기화가 되어야 하기 때문이다.
    • !가 붙어있는 initializer은 사용 가능하다.(비추천)
  • 반대로 failable initializer에서는 다른 init을 사용하지 못하는 제약은 없다.
    • 슈퍼클래스의 failable initializer을 서브클래스에서 non으로 구현해도 ok. 다만 상위 구현을 호출할 때 강제추출 연산자를 사용해야 함.
profile
iOS 개발자가 되기 위한 스터디룸...

0개의 댓글