-
Swift 5.6 Initialization기술/iOS 2022. 3. 20. 17:51
Initialization
Settings Initial Values for Stored Properties
클래스와 구조체는 해당 클래스 또는 구조체의 인스턴스가 생성될 때까지 모든 저장된 프로퍼티에 적절한 초기값을 반드시 설정해야합니다. 저장된 프로퍼티는 확정되지 않은 상태로 남아있을 수 없습니다.
추기화 구문 내에서 저장된 프로퍼티에 초기값을 설정하거나 프로퍼티의 저으이 부분에서 기본 프로퍼티 값을 할당할 수 있습니다.
Initializers
초기화 구문은 특정 타입의 새로운 인스턴스를 생성하기 위해 호출됩니다. 가장 간다한 형식으로 초기화 구문은 init 키워드를 작성하여 파라미터가 없는 인스턴스 메서드와 같습니다.
init() {}
Default Property Values
초기화 구문 내에서 저장된 프로퍼티에 초기값을 설정할 수 있습니다. 또는 프로퍼티의 선언의 일부로 기본 프로퍼티 값을 지정합니다. 프로퍼티가 정의될 때 프로퍼티 초기값을 할당하는 것으로 기본 프로퍼티 값을 지정합니다.
Customizing Initialization
Initialization Parameters
초기화 단계를 사용자화 하는 값의 타입과 이름을 저으이하기 위해 초기화의 정의의 부분으로 초기화 파라미터를 제공할 수 있습니다. 초기화 파라미터는 함수와 메서드 파라미터로 동일한 기능과 구문을 가지고 있습니다.
Parameter Names and Argument Labels
함수와 메서드 라미터와 마찬가지로 초기화 파라미터는 초기화 구문의 바디 내에서 사용하는 파라미터 명과 초기화 구문을 호출할 때 사용하는 인자 라벨 모두 가질 수 있습니다.
그러나 초기화 구문은 함수와 메서드처럼 소괄호 앞에 식별 함수 이름을 가지지 않습니다. 따라서 초기화 구문의 파라미터 이름과 타입은 어떤 초기화 구문을 호출해야하는지 식별하는데 중요한 역할을 합니다. 이러한 이유 때문에 Swift 는 초기화 구문에서 라벨을 제공하지 않으면 모든 파라미터에 대해 자동적으로 인수 라벨을 제공합니다.
Initializer Parameters Without Argument Labels
초기화 구문 파라미터에 인자 라벨 사용을 원치 않을 경우 명시적으로 인자 라벨 대신에 언더바를 작성하여 기본 동작을 재정의 합니다.
Optional Property Types
사용자 타입이 값이 초기화 동안 설정될 수 없거나 추후에 “값 없음" 을 가질 수 있기 때문에 논리적으로 “값 없음”을 가질 수 있는 하나의 저장된 프로퍼티를 가지고 있다면 옵셔널 타입으로 프로퍼티를 선언합니다. 옵셔널 타입의 프로퍼티는 자동적으로 초기화 동안 “아직 값 없음" 을 가진다는 의도를 위해 nil 의 값으로 초기화 됩니다.
Assigning Constant Properties During Initialization
초기화 중 언제든지 프로퍼티 상수에 값을 할당할 수 있습니다.
Default Initializers
Swift 는 모든 프로퍼티에 대해 기본 값을 제공하고 적어도 하나의 초기화 구문을 제공하지 않는 모든 구조체 또는 클래스에 대해 기본 초기화 구문을 제공합니다. 기본 초기화 구문은 모든 프로퍼티가 기본 값으로 설정된 새로운 인스턴스를 생성합니다.
Memberwise Initializers for Structure Types
구조체 타입은 자신의 사용자화 초기화 구문을 정의하지 않으면 자동적으로 멤버 별 초기화 구문을 받습니다. 기본 초기화 구문과 다르게 구조체는 기본 값을 가지지 않은 저장된 프로퍼티라도 멤버 별 초기화 구문을 받습니다.
멤버 별 초기화 구문은 새로운 구조체 인스턴스에 멤버 프로퍼티를 초기화 하기 위한 짧은 구문 방법입니다. 새로운 인스턴스의 프로퍼티를 위한 초기화 값은 이름으로 멤버 별 초기화 구문으로 전달될 수 있습니다.
Initializer Delegation for Value Types
초기화 구문은 인스턴스의 초기화 부분을 수행하기 위해 다른 초기화 구문을 호출할 수 있습니다. 초기화 구문 위임이라는 이 프로세스는 여러 초기화 구문에서 코드가 중복되는 것을 방지 합니다.
초기화 구문 위임이 동작하는 방식과 허용하는 위임 혁시에 대한 규칙은 값 타입과 클래스 타입에 따라 다릅니다. 값 타입은 상속을 지원하지 않고 초기화 구문 위임 프로세스는 자신이 제공하는 다른 초기화 구문에만 위임할 수 있으므로 비교적 간단합니다. 그러나 클래스는 상속에서 설명했듯 다른 클래스에서 상속할 수 있습니다. 이는 클래스는 상속하는 모든 저장된 프로퍼티에 초기화 중 적절한 값이 할당되도록 하는 추가 책임이 있음을 의미합니다.
값 타입의 경우 자체 사용자화 초기화 구문을 작성할 때 같은 값 타입으로부터 초기화 구문을 참조하기 위해 self.init 을 호출합니다. 초기화 구문 내에서만 호출할 수 있습니다.
값 타입에 대해 사용자 화 초기화 구문을 정의한다면 그 타입에 대해 기본 초기화 구문 또는 구조체의 경우 멤버 별 초기화 구문에 더이상 접근할 수 없습니다. 이 제약은 자동 초기화 구문을 사용하는 누군가가 더 복잡한 초기화 구문에서 제공하는 추가 필수 설정을 실수로 우회하는 것을 방지합니다.
struct Rect { var origin = Point() var size = Size() init() {} init(origin: Point, size: Size) { self.origin = origin self.size = size } init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) } }
Class Inheritance and Initialization
상위 클래스로부터 상속한 클래스의 모든 프로퍼티를 포함하는 모든 클래스의 저장된 프로퍼티는 초기화 중 반드시 초기값이 할당되어야 합니다.
Swift 는 모든 저장된 프로퍼티가 초기값을 받을 수 있도록 클래스 타입에 대해 2가지의 초기화 구문을 정의합니다. 이들은 지정된 초기화 구문의 편의 초기화 구문으로 알려져 있습니다.
? Designated Initializers and Convenience Initializers
지정된 초기화 구문은 클래스에 주 초기화 구문입니다. 지정된 초기화 구문은 해당 클래스에 의해 도입된 모든 프로퍼티를 완벽하게 초기화 하고 적절한 상위 클래스 초기화를 호출하여 상위 클래스 체인까지 초기화 프로세스를 계속합니다.
클래스는 지정된 초기화 구문의 거의 없는 경향이 있으며 클래스에 하나만 있는 경우가 일반적입니다. 지정된 초기화 구문은 초기화가 수행되고 초기화 프로세스가 상위 클래스 체인까지 계속되는 funel 지점입니다.
모든 클래스는 적어도 하나의 지정된 초기화 구문을 가지고 있어야 합니다. 경우에 따라 이 요구사항은 상위 클래스에서 하나 이상의 지정된 초기화 구문을 상속하는 것으로 충족됩니다.
편의 초기화 구문은 클래스에 대해 초기화 구문을 지원하는 보조 초기화 구문입니다. 지정된 초기화 구문의 파라미터를 기본 값으로 설정하여 편의 초기화 구문과 동일한 클래스에서 지정된 초기화 구문을 호출하도록 편의 초기화 구문을 정의할 수 있습니다. 특정 사용 케이스 또는 입력 값 타입에 대한 해당 클래스의 인스턴스를 생성하기 위해 편의 초기화 구문을 정의할 수도 있습니다.
클래스에 필요하지 않은 경우 편의 초기화 구문을 제공할 필요가 없습니다. 일반적인 초기화 패턴에 대한 바로가기나 시간을 절약하거나 클래스 초기화를 더 명확하게 만들 때마다 편리한 초기화 구문을 만듭니다.
Syntax for Designated and Convenience Initializers
클래스에 대한 지정된 초기화 구문은 값 타입에 대한 간단한 초기화 구문과 동일한 방법으로 작성됩니다.
편의 초기화 구문은 같은 스타일로 작성ㅇ되지만 공백으로 구분하여 init 키워드 전에 convenience 수정자를 작성합니다.
**convenience init 은 다른 init 을 호출할 때 명시적으로 나타내기 위한 키워드인가?**
지정된 초기화 구문은 단순히 init 문 인가?
? Initializer Delegation for Class Types
지정된 초기화 구문과 편의 초기화 구문 사이의 관계를 단순화 하기 위해 Swift 는 초기화 사이의 위임 호출에 대한 3가지 규칙을 적용합니다.
- 규칙 1
- 지정된 초기화 구문은 상위 클래스로부터 지정된 초기화 구문을 호출해야합니다.
- 규칙 2
- 편의 초기화 구문은 같은 클래스로부터 다른 초기화 구문을 호출해야 합니다.
- 규칙 3
- 편의 초기화 구문은 궁극적으로 지정된 초기화 구문을 호출해야만 합니다.
이것을 기억하는 간단한 방법은 아래와 같습니다.
- 지정된 초기화 구문은 항상 위로 위임해야합니다.
- 편의 초기화 구문은 항상 옆으로 위임해야 합니다.
? Two-Phase Initialization
Swift 에서 클래스를 2단계 프로세스로 초기화합니다. 첫번째 단계에서는 각 저장된 프로퍼티가 해당 프로퍼티를 도입한 클래스에 의해 초기값이 할당됩니다. 모든 저장된 프로퍼티에 초기 상태가 결정되면 두번째 단계가 시작되고 새 인스턴스가 사용될 준비가 된 것으로 간주하기 전 각 클래스에 저장된 프로퍼티를 사용자 화 할 수 있는 기회가 주어집니다.
2단계 초기화 프로세스를 사용하면 초기화를 안전하게 수행하는 동시에 클래스 계층도 각 클래스에 완전한 유연성을 제공합니다. 2단계 초기화는 프로퍼티 값이 초기화 되기 전 접근하는 것을 막고 다른 초기화 구문이 예기치 않게 다른 값을 설정하는 것을 막습니다.
Swift 컴파일러는 에러 없이 2단계 초기화가 완료되었는지 확인하기 위한 4가지 검사를 합니다.
- 안전 점검 1
- 지정된 초기화 구문은 상위 클래스 초기화 구문에 위임되기 전 클래스에 의해 도입된 모든 프로퍼티가 초기화 되었는지 확인합니다.
- 안전 점검 2
- 지정된 초기화 구문은 상속된 프로퍼티에 값을 할당하기 전 상위 클래스 초기화 구문에 위임해야 합니다. 그렇지 않으면 지정된 초기화 구문에 할당한 새로운 값 자체 초기화 부분을 상위 클래스에 의해 덮어 쓰여집니다.
- 이쪽이 잘 감이 안잡히네
- 안전 점검 3
- 편의 초기화 구문은 모든 프로퍼티에 값을 할당하기 전 다른 초기화 구문에 위임해야 합니다. 그렇지 않으면 편의 초기화 구문에 할당한 새로운 값 자체 클래스의 지정된 초기화 구문에 의해 덮어쓰여집니다.
- 안전 점검 4
- 초기화 구문은 첫번째 초기화가 완료될 때까지 인스터스 메서드 호출을 하거나 인스턴스 프로퍼티의 갑슬 읽거나 self 를 값으로 참조할 수 없습니다.
- 첫번째 초기화?
클래스 인스턴스는 첫번째 단계가 끝날때까지 완전히 유요하지 않습니다. 첫번째 단계까 끝날 때 클래스 인스턴스가 유효한 것으로 판단된 후에만 프로퍼티는 접근할 수 있고 메서드를 호출할 수 있습니다.
위의 4개의 안전점검을 기반으로 2단계 초기화가 수행되는 방식은 아래와 같습니다.
- 즉, 내 프로퍼티는 수정 가능해도 super.init 을 호출하기 전까지 부모의 프로퍼티를 변경하거나 사용하지 못한다는 뜻?
1단계
- 지정된 또는 편의 초기화 구문은 클래스에서 호출됩니다.
- 클래스에 새로운 인스턴스에 대한 메모리는 할당됩니다. 메모리는 아직 초기화되지 않았습니다.
- 클래스에 대한 지정된 초기화 구문은 클래스에 의해 도입된 모든 저장된 프로퍼티가 값을 가지고 있는지 확인합니다. 이러한 저장된 프로퍼티에 대한 메모리는 초기화 됩니다.
- 지정된 초기화 구문은 자체 저장된 프로퍼티에 동일한 작업을 수행하기 위해 상위 클래스 초기화 구문에 전달됩니다.
- 이것은 최상위 체인까지 클래스 상속 체인 위로 계속 됩니다.
- 최상위 체인에 도달하고 체인에 마지막 클래스가 모든 저장된 프로퍼티가 값을 가지고 있다고 확인하면 인스턴스의 메모리는 완벽하게 초기화 되었다고 간주하고 첫번째 단계가 완료됩니다.
2단계
- 체인의 최상위에서 아래로 내려가면서 체인에 각 지정된 초기화 구문은 인스턴스를 추가로 사용자 정의할 수 있는 옵션이 있습니다. 초기화 구문은 이제 self 에 접근할 수 있으며 프로퍼티를 수정하고 인스턴스 메서드를 호출하는 등 작업을 수행할 수 있습니다.
- 마지막으로 체인에 모든 편의 초기화 구문은 인스턴스를 사용자 정의하고 self 로 작업할 수 있는 옵션이 있습니다.
? Initializer Inheritance and Overriding
사용자 정의 하위 클래스가 상위 클래스와 동일한 초기화 구문 중 하나 이상을 표시하려면 하위 클래스 내에서 해당 초기화 구문의 사용자 정의 구현을 제공할 수 있습니다.
상위 클래스에 지정된 초기화 구문과 일치하는 하위 클래스 초기화 구문을 작성할 때 지정된 초기화 구문의 재정의를 효과적으로 제공합니다. 따라서 하위 클래스의 초기화 구문 정의 전에 override 수식어를 작성해야 합니다.
반대로 상위 클래스에 편의 초기화 구문과 일치하는 하위 클래스 초기화 구문을 작성하는 경우 Initializer Delegation for Class Types 에서 설명한 규칙에 따라 해당 상위 클래스 편의 초기화 구문은 하위 클래스에서 직접 호출할 수 없습니다. 따라서 하위 클래스는 상위 클래스 초기화 구문에 재정의를 제공하지 않습니다. 결과적으로 상위 클래스 편의 초기화 구문의 일치하는 구현을 제공할 때 override 수식어를 작성하지 않습니다.
- override init 했을 때 반드시 super.init 을 호출해야 하는가?
상위 클래스가 인자가 없는 지정된 초기화 구문을 가지고 있다면 모든 하위 클래스의 저장된 프로퍼티에 값을 할당한 후에 값을 할당한 후에 super.init() 을 호출을 생략할 수 있습니다.
? Automatic Initializer Inheritance
위에서 언급했듯 하위 클래스는 기본적으로 상위 클래스 초기화 구문을 상속하지 않습니다. 그러나 특정 조건이 충족하면 상위 클래스 초기화 구문은 자동으로 상속됩니다. 실제로 이것은 대부분의 경우에 초기화 구문 재정의를 작성할 필요가 없으며 안전하며 상위 클래스 초기화 구문을 최소한의 노력으로 상속할 수 있습니다.
하위 클래스에 도입한 모든 새로운 프로퍼티에 기본값을 제공하면 아래 두가지 규칙이 적용됩니다.
규칙 1
하위 클래스가 지정된 초기화 구문을 정의하지 않았다면 자동으로 상위 클래스에 지정된 초기화 구문을 모두 상속합니다.
규칙 2
하위 클래스가 규칙 1에 따라 상속하거나 정의의 부분으로 사용자 정의 구현을 제공하면 모든 상위 클래스 지정된 초기화 구문의 구현을 제공하면 모든 상위 클래스 편의 초기화 구문을 자동으로 상속합니다.
이러한 규칙은 하위 클래스가 편의 초기화 구문을 추가할 때도 적용됩니다.
? Designate and Convenience Initializers in Action
Failable Initializers
초기화가 실패할 수 있는 것에 대한 클래스 구조체 또는 열거형을 정의하는 것이 유용할 수 있습니다. 이 실패는 유효하지 않은 초기화 파라미터 값, 필수 외부 리소스 부재 또는 초기화 성공을 방해하는 기타 다른 조건에 의해 트리거 될 수 있습니다.
실패할 수 있는 초기화 조건을 대처하려면 실패 가능한 초기화 구문을 클래스, 구조체, 또는 열거형의 일부로 정의합니다. init 키워드 뒤에 물음표를 표기하여 초기화를 작성합니다.
NOTE 동일한 파라미터 타입과 이름으로 실패 가능한 초기화 구문과 실패 불가능한 초기화 구문을 정의할 수 없습니다.
실패 가능한 초기화 구문은 초기화 타입의 옵셔널 값을 생성합니다. 실패 가능한 초기화 구문 내에 return nil 을 작성하여 초기화 실패가 트리거 될 수 있는 지점을 나타냅니다.
NOTE 엄밀히 말하면 초기화 구문은 값을 반환하지 않습니다. 오히려 초기화 구문의 역할은 초기화가 끝날 떄까지 self 를 완전하고 정확하게 초기화 되도록 하는 것입니다. 초기화가 실패를 트리거하기 위해 return nil 을 작성하지만 성공을 나타내기 위해 return 키워드를 사용하지 않습니다.
이건 좀 애매하네...
? The Init! Failable Initializer
물음표 대신 느낌표를 사용하면 런타임 에러가 나는 느낌?
Required Initializers
클래스 초기화 구문 정의 앞에 required 수식어를 작성하면 모든 하위 클래스가 해당 초기화 구문을 구현해야 함을 나타냅니다.
또한 초기화 구문 요구사항이 체인의 추가 하위 클래스에 적용됨을 나타내기 위해 필수 초기화 구문에 모든 하우 클래스 구현 전에 required 수식어를 작성해야 합니다. 지정된 필수 초기화 구문을 재정의 할 때 override 수식어를 작성하지 않습니다.
Initialization
Settings Initial Values for Stored Properties
클래스와 구조체는 해당 클래스 또는 구조체의 인스턴스가 생성될 때까지 모든 저장된 프로퍼티에 적절한 초기값을 반드시 설정해야합니다. 저장된 프로퍼티는 확정되지 않은 상태로 남아있을 수 없습니다.
추기화 구문 내에서 저장된 프로퍼티에 초기값을 설정하거나 프로퍼티의 저으이 부분에서 기본 프로퍼티 값을 할당할 수 있습니다.
Initializers
초기화 구문은 특정 타입의 새로운 인스턴스를 생성하기 위해 호출됩니다. 가장 간다한 형식으로 초기화 구문은 init 키워드를 작성하여 파라미터가 없는 인스턴스 메서드와 같습니다.
init() {}
Default Property Values
초기화 구문 내에서 저장된 프로퍼티에 초기값을 설정할 수 있습니다. 또는 프로퍼티의 선언의 일부로 기본 프로퍼티 값을 지정합니다. 프로퍼티가 정의될 때 프로퍼티 초기값을 할당하는 것으로 기본 프로퍼티 값을 지정합니다.
Customizing Initialization
Initialization Parameters
초기화 단계를 사용자화 하는 값의 타입과 이름을 저으이하기 위해 초기화의 정의의 부분으로 초기화 파라미터를 제공할 수 있습니다. 초기화 파라미터는 함수와 메서드 파라미터로 동일한 기능과 구문을 가지고 있습니다.
Parameter Names and Argument Labels
함수와 메서드 라미터와 마찬가지로 초기화 파라미터는 초기화 구문의 바디 내에서 사용하는 파라미터 명과 초기화 구문을 호출할 때 사용하는 인자 라벨 모두 가질 수 있습니다.
그러나 초기화 구문은 함수와 메서드처럼 소괄호 앞에 식별 함수 이름을 가지지 않습니다. 따라서 초기화 구문의 파라미터 이름과 타입은 어떤 초기화 구문을 호출해야하는지 식별하는데 중요한 역할을 합니다. 이러한 이유 때문에 Swift 는 초기화 구문에서 라벨을 제공하지 않으면 모든 파라미터에 대해 자동적으로 인수 라벨을 제공합니다.
Initializer Parameters Without Argument Labels
초기화 구문 파라미터에 인자 라벨 사용을 원치 않을 경우 명시적으로 인자 라벨 대신에 언더바를 작성하여 기본 동작을 재정의 합니다.
Optional Property Types
사용자 타입이 값이 초기화 동안 설정될 수 없거나 추후에 “값 없음" 을 가질 수 있기 때문에 논리적으로 “값 없음”을 가질 수 있는 하나의 저장된 프로퍼티를 가지고 있다면 옵셔널 타입으로 프로퍼티를 선언합니다. 옵셔널 타입의 프로퍼티는 자동적으로 초기화 동안 “아직 값 없음" 을 가진다는 의도를 위해 nil 의 값으로 초기화 됩니다.
Assigning Constant Properties During Initialization
초기화 중 언제든지 프로퍼티 상수에 값을 할당할 수 있습니다.
Default Initializers
Swift 는 모든 프로퍼티에 대해 기본 값을 제공하고 적어도 하나의 초기화 구문을 제공하지 않는 모든 구조체 또는 클래스에 대해 기본 초기화 구문을 제공합니다. 기본 초기화 구문은 모든 프로퍼티가 기본 값으로 설정된 새로운 인스턴스를 생성합니다.
Memberwise Initializers for Structure Types
구조체 타입은 자신의 사용자화 초기화 구문을 정의하지 않으면 자동적으로 멤버 별 초기화 구문을 받습니다. 기본 초기화 구문과 다르게 구조체는 기본 값을 가지지 않은 저장된 프로퍼티라도 멤버 별 초기화 구문을 받습니다.
멤버 별 초기화 구문은 새로운 구조체 인스턴스에 멤버 프로퍼티를 초기화 하기 위한 짧은 구문 방법입니다. 새로운 인스턴스의 프로퍼티를 위한 초기화 값은 이름으로 멤버 별 초기화 구문으로 전달될 수 있습니다.
Initializer Delegation for Value Types
초기화 구문은 인스턴스의 초기화 부분을 수행하기 위해 다른 초기화 구문을 호출할 수 있습니다. 초기화 구문 위임이라는 이 프로세스는 여러 초기화 구문에서 코드가 중복되는 것을 방지 합니다.
초기화 구문 위임이 동작하는 방식과 허용하는 위임 혁시에 대한 규칙은 값 타입과 클래스 타입에 따라 다릅니다. 값 타입은 상속을 지원하지 않고 초기화 구문 위임 프로세스는 자신이 제공하는 다른 초기화 구문에만 위임할 수 있으므로 비교적 간단합니다. 그러나 클래스는 상속에서 설명했듯 다른 클래스에서 상속할 수 있습니다. 이는 클래스는 상속하는 모든 저장된 프로퍼티에 초기화 중 적절한 값이 할당되도록 하는 추가 책임이 있음을 의미합니다.
값 타입의 경우 자체 사용자화 초기화 구문을 작성할 때 같은 값 타입으로부터 초기화 구문을 참조하기 위해 self.init 을 호출합니다. 초기화 구문 내에서만 호출할 수 있습니다.
값 타입에 대해 사용자 화 초기화 구문을 정의한다면 그 타입에 대해 기본 초기화 구문 또는 구조체의 경우 멤버 별 초기화 구문에 더이상 접근할 수 없습니다. 이 제약은 자동 초기화 구문을 사용하는 누군가가 더 복잡한 초기화 구문에서 제공하는 추가 필수 설정을 실수로 우회하는 것을 방지합니다.
struct Rect { var origin = Point() var size = Size() init() {} init(origin: Point, size: Size) { self.origin = origin self.size = size } init(center: Point, size: Size) { let originX = center.x - (size.width / 2) let originY = center.y - (size.height / 2) self.init(origin: Point(x: originX, y: originY), size: size) } }
Class Inheritance and Initialization
상위 클래스로부터 상속한 클래스의 모든 프로퍼티를 포함하는 모든 클래스의 저장된 프로퍼티는 초기화 중 반드시 초기값이 할당되어야 합니다.
Swift 는 모든 저장된 프로퍼티가 초기값을 받을 수 있도록 클래스 타입에 대해 2가지의 초기화 구문을 정의합니다. 이들은 지정된 초기화 구문의 편의 초기화 구문으로 알려져 있습니다.
? Designated Initializers and Convenience Initializers
지정된 초기화 구문은 클래스에 주 초기화 구문입니다. 지정된 초기화 구문은 해당 클래스에 의해 도입된 모든 프로퍼티를 완벽하게 초기화 하고 적절한 상위 클래스 초기화를 호출하여 상위 클래스 체인까지 초기화 프로세스를 계속합니다.
클래스는 지정된 초기화 구문의 거의 없는 경향이 있으며 클래스에 하나만 있는 경우가 일반적입니다. 지정된 초기화 구문은 초기화가 수행되고 초기화 프로세스가 상위 클래스 체인까지 계속되는 funel 지점입니다.
모든 클래스는 적어도 하나의 지정된 초기화 구문을 가지고 있어야 합니다. 경우에 따라 이 요구사항은 상위 클래스에서 하나 이상의 지정된 초기화 구문을 상속하는 것으로 충족됩니다.
편의 초기화 구문은 클래스에 대해 초기화 구문을 지원하는 보조 초기화 구문입니다. 지정된 초기화 구문의 파라미터를 기본 값으로 설정하여 편의 초기화 구문과 동일한 클래스에서 지정된 초기화 구문을 호출하도록 편의 초기화 구문을 정의할 수 있습니다. 특정 사용 케이스 또는 입력 값 타입에 대한 해당 클래스의 인스턴스를 생성하기 위해 편의 초기화 구문을 정의할 수도 있습니다.
클래스에 필요하지 않은 경우 편의 초기화 구문을 제공할 필요가 없습니다. 일반적인 초기화 패턴에 대한 바로가기나 시간을 절약하거나 클래스 초기화를 더 명확하게 만들 때마다 편리한 초기화 구문을 만듭니다.
Syntax for Designated and Convenience Initializers
클래스에 대한 지정된 초기화 구문은 값 타입에 대한 간단한 초기화 구문과 동일한 방법으로 작성됩니다.
편의 초기화 구문은 같은 스타일로 작성ㅇ되지만 공백으로 구분하여 init 키워드 전에 convenience 수정자를 작성합니다.
**convenience init 은 다른 init 을 호출할 때 명시적으로 나타내기 위한 키워드인가?**
지정된 초기화 구문은 단순히 init 문 인가?
? Initializer Delegation for Class Types
지정된 초기화 구문과 편의 초기화 구문 사이의 관계를 단순화 하기 위해 Swift 는 초기화 사이의 위임 호출에 대한 3가지 규칙을 적용합니다.
- 규칙 1
- 지정된 초기화 구문은 상위 클래스로부터 지정된 초기화 구문을 호출해야합니다.
- 규칙 2
- 편의 초기화 구문은 같은 클래스로부터 다른 초기화 구문을 호출해야 합니다.
- 규칙 3
- 편의 초기화 구문은 궁극적으로 지정된 초기화 구문을 호출해야만 합니다.
이것을 기억하는 간단한 방법은 아래와 같습니다.
- 지정된 초기화 구문은 항상 위로 위임해야합니다.
- 편의 초기화 구문은 항상 옆으로 위임해야 합니다.
? Two-Phase Initialization
Swift 에서 클래스를 2단계 프로세스로 초기화합니다. 첫번째 단계에서는 각 저장된 프로퍼티가 해당 프로퍼티를 도입한 클래스에 의해 초기값이 할당됩니다. 모든 저장된 프로퍼티에 초기 상태가 결정되면 두번째 단계가 시작되고 새 인스턴스가 사용될 준비가 된 것으로 간주하기 전 각 클래스에 저장된 프로퍼티를 사용자 화 할 수 있는 기회가 주어집니다.
2단계 초기화 프로세스를 사용하면 초기화를 안전하게 수행하는 동시에 클래스 계층도 각 클래스에 완전한 유연성을 제공합니다. 2단계 초기화는 프로퍼티 값이 초기화 되기 전 접근하는 것을 막고 다른 초기화 구문이 예기치 않게 다른 값을 설정하는 것을 막습니다.
Swift 컴파일러는 에러 없이 2단계 초기화가 완료되었는지 확인하기 위한 4가지 검사를 합니다.
- 안전 점검 1
- 지정된 초기화 구문은 상위 클래스 초기화 구문에 위임되기 전 클래스에 의해 도입된 모든 프로퍼티가 초기화 되었는지 확인합니다.
- 안전 점검 2
- 지정된 초기화 구문은 상속된 프로퍼티에 값을 할당하기 전 상위 클래스 초기화 구문에 위임해야 합니다. 그렇지 않으면 지정된 초기화 구문에 할당한 새로운 값 자체 초기화 부분을 상위 클래스에 의해 덮어 쓰여집니다.
- 이쪽이 잘 감이 안잡히네
- 안전 점검 3
- 편의 초기화 구문은 모든 프로퍼티에 값을 할당하기 전 다른 초기화 구문에 위임해야 합니다. 그렇지 않으면 편의 초기화 구문에 할당한 새로운 값 자체 클래스의 지정된 초기화 구문에 의해 덮어쓰여집니다.
- 안전 점검 4
- 초기화 구문은 첫번째 초기화가 완료될 때까지 인스터스 메서드 호출을 하거나 인스턴스 프로퍼티의 갑슬 읽거나 self 를 값으로 참조할 수 없습니다.
- 첫번째 초기화?
클래스 인스턴스는 첫번째 단계가 끝날때까지 완전히 유요하지 않습니다. 첫번째 단계까 끝날 때 클래스 인스턴스가 유효한 것으로 판단된 후에만 프로퍼티는 접근할 수 있고 메서드를 호출할 수 있습니다.
위의 4개의 안전점검을 기반으로 2단계 초기화가 수행되는 방식은 아래와 같습니다.
- 즉, 내 프로퍼티는 수정 가능해도 super.init 을 호출하기 전까지 부모의 프로퍼티를 변경하거나 사용하지 못한다는 뜻?
1단계
- 지정된 또는 편의 초기화 구문은 클래스에서 호출됩니다.
- 클래스에 새로운 인스턴스에 대한 메모리는 할당됩니다. 메모리는 아직 초기화되지 않았습니다.
- 클래스에 대한 지정된 초기화 구문은 클래스에 의해 도입된 모든 저장된 프로퍼티가 값을 가지고 있는지 확인합니다. 이러한 저장된 프로퍼티에 대한 메모리는 초기화 됩니다.
- 지정된 초기화 구문은 자체 저장된 프로퍼티에 동일한 작업을 수행하기 위해 상위 클래스 초기화 구문에 전달됩니다.
- 이것은 최상위 체인까지 클래스 상속 체인 위로 계속 됩니다.
- 최상위 체인에 도달하고 체인에 마지막 클래스가 모든 저장된 프로퍼티가 값을 가지고 있다고 확인하면 인스턴스의 메모리는 완벽하게 초기화 되었다고 간주하고 첫번째 단계가 완료됩니다.
2단계
- 체인의 최상위에서 아래로 내려가면서 체인에 각 지정된 초기화 구문은 인스턴스를 추가로 사용자 정의할 수 있는 옵션이 있습니다. 초기화 구문은 이제 self 에 접근할 수 있으며 프로퍼티를 수정하고 인스턴스 메서드를 호출하는 등 작업을 수행할 수 있습니다.
- 마지막으로 체인에 모든 편의 초기화 구문은 인스턴스를 사용자 정의하고 self 로 작업할 수 있는 옵션이 있습니다.
? Initializer Inheritance and Overriding
사용자 정의 하위 클래스가 상위 클래스와 동일한 초기화 구문 중 하나 이상을 표시하려면 하위 클래스 내에서 해당 초기화 구문의 사용자 정의 구현을 제공할 수 있습니다.
상위 클래스에 지정된 초기화 구문과 일치하는 하위 클래스 초기화 구문을 작성할 때 지정된 초기화 구문의 재정의를 효과적으로 제공합니다. 따라서 하위 클래스의 초기화 구문 정의 전에 override 수식어를 작성해야 합니다.
반대로 상위 클래스에 편의 초기화 구문과 일치하는 하위 클래스 초기화 구문을 작성하는 경우 Initializer Delegation for Class Types 에서 설명한 규칙에 따라 해당 상위 클래스 편의 초기화 구문은 하위 클래스에서 직접 호출할 수 없습니다. 따라서 하위 클래스는 상위 클래스 초기화 구문에 재정의를 제공하지 않습니다. 결과적으로 상위 클래스 편의 초기화 구문의 일치하는 구현을 제공할 때 override 수식어를 작성하지 않습니다.
- override init 했을 때 반드시 super.init 을 호출해야 하는가?
상위 클래스가 인자가 없는 지정된 초기화 구문을 가지고 있다면 모든 하위 클래스의 저장된 프로퍼티에 값을 할당한 후에 값을 할당한 후에 super.init() 을 호출을 생략할 수 있습니다.
? Automatic Initializer Inheritance
위에서 언급했듯 하위 클래스는 기본적으로 상위 클래스 초기화 구문을 상속하지 않습니다. 그러나 특정 조건이 충족하면 상위 클래스 초기화 구문은 자동으로 상속됩니다. 실제로 이것은 대부분의 경우에 초기화 구문 재정의를 작성할 필요가 없으며 안전하며 상위 클래스 초기화 구문을 최소한의 노력으로 상속할 수 있습니다.
하위 클래스에 도입한 모든 새로운 프로퍼티에 기본값을 제공하면 아래 두가지 규칙이 적용됩니다.
규칙 1
하위 클래스가 지정된 초기화 구문을 정의하지 않았다면 자동으로 상위 클래스에 지정된 초기화 구문을 모두 상속합니다.
규칙 2
하위 클래스가 규칙 1에 따라 상속하거나 정의의 부분으로 사용자 정의 구현을 제공하면 모든 상위 클래스 지정된 초기화 구문의 구현을 제공하면 모든 상위 클래스 편의 초기화 구문을 자동으로 상속합니다.
이러한 규칙은 하위 클래스가 편의 초기화 구문을 추가할 때도 적용됩니다.
? Designate and Convenience Initializers in Action
Failable Initializers
초기화가 실패할 수 있는 것에 대한 클래스 구조체 또는 열거형을 정의하는 것이 유용할 수 있습니다. 이 실패는 유효하지 않은 초기화 파라미터 값, 필수 외부 리소스 부재 또는 초기화 성공을 방해하는 기타 다른 조건에 의해 트리거 될 수 있습니다.
실패할 수 있는 초기화 조건을 대처하려면 실패 가능한 초기화 구문을 클래스, 구조체, 또는 열거형의 일부로 정의합니다. init 키워드 뒤에 물음표를 표기하여 초기화를 작성합니다.
NOTE 동일한 파라미터 타입과 이름으로 실패 가능한 초기화 구문과 실패 불가능한 초기화 구문을 정의할 수 없습니다.
실패 가능한 초기화 구문은 초기화 타입의 옵셔널 값을 생성합니다. 실패 가능한 초기화 구문 내에 return nil 을 작성하여 초기화 실패가 트리거 될 수 있는 지점을 나타냅니다.
NOTE 엄밀히 말하면 초기화 구문은 값을 반환하지 않습니다. 오히려 초기화 구문의 역할은 초기화가 끝날 떄까지 self 를 완전하고 정확하게 초기화 되도록 하는 것입니다. 초기화가 실패를 트리거하기 위해 return nil 을 작성하지만 성공을 나타내기 위해 return 키워드를 사용하지 않습니다.
이건 좀 애매하네...
? The Init! Failable Initializer
물음표 대신 느낌표를 사용하면 런타임 에러가 나는 느낌?
Required Initializers
클래스 초기화 구문 정의 앞에 required 수식어를 작성하면 모든 하위 클래스가 해당 초기화 구문을 구현해야 함을 나타냅니다.
또한 초기화 구문 요구사항이 체인의 추가 하위 클래스에 적용됨을 나타내기 위해 필수 초기화 구문에 모든 하우 클래스 구현 전에 required 수식어를 작성해야 합니다. 지정된 필수 초기화 구문을 재정의 할 때 override 수식어를 작성하지 않습니다.
'기술 > iOS' 카테고리의 다른 글
Swift 5.6 Optional Chaining (0) 2022.03.20 Swift 5.6 Deinitialization (0) 2022.03.20 Swift 5.6 Inheritance (0) 2022.03.20 Swift 5.6 Subscripts (0) 2022.03.20 Swift 5.6 Methods (0) 2022.03.20 TAG
- 규칙 1