멤버의 확장(생성자)
- 확장을 사용하여 기존 타입에 새로운 생성자를 추가할 수 있다
- 구조체와 클래스에서 확장된 생성자를 정의하는 방식이 다르다
구조체와 클래스의 생성자 확장 차이
구조체 (Struct):
- 구조체는 기본적으로 지정 생성자만 존재한다 (편의 생성자는 존재하지 않음)
- 구조체는 상속과 관련이 없기 때문에 지정 생성자를 자유롭게 구현할 수 있다
- 확장을 통해 편의 생성자와 비슷하게 본체의 지정 생성자를 호출하는 생성자도 구현할 수 있다
- 기존의 기본 생성자와 멤버와이즈 생성자는 자동으로 제공된다
- 하지만 본체에서 직접 지정 생성자를 구현하면 기본 생성자와 멤버와이즈 생성자는 제공되지 않는다
- 예외적으로, 모든 저장 속성에 기본값을 제공하고, 본체에서 직접 생성자를 구현하지 않은 경우, 확장에서 정의한 생성자와 기존의 기본 생성자 및 멤버와이즈 생성자가 함께 제공된다
클래스 (Class):
- 클래스는 확장에서 편의 생성자(convenience initializer)만 추가할 수 있다
- 확장에서 지정 생성자를 정의할 수 없고, 소멸자도 추가할 수 없다
- 편의 생성자는 기존 지정 생성자를 호출하는 방식으로 구현해야 한다
- 기존의 지정 생성자와 확장에서 정의한 편의 생성자를 함께 사용할 수 있다
구조체 - 생성자 확장의 예시 (예시: Triangle)
struct Triangle {
var base: Double = 1.0
var height: Double = 1.0
}
let defaultTriangle = Triangle()
let customTriangle = Triangle(base: 5.0, height: 3.0)
extension Triangle {
init(area: Double) {
let calculatedBase = (area * 2).squareRoot()
let calculatedHeight = (area * 2).squareRoot()
self.init(base: calculatedBase, height: calculatedHeight)
}
init(copyFrom triangle: Triangle) {
self.init(base: triangle.base, height: triangle.height)
}
}
let areaTriangle = Triangle(area: 6.0)
let copyTriangle = Triangle(copyFrom: customTriangle)
print("Area Triangle: Base = \(areaTriangle.base), Height = \(areaTriangle.height)")
print("Copy Triangle: Base = \(copyTriangle.base), Height = \(copyTriangle.height)")
Triangle 구조체는 base와 height 속성을 가진다
- 기본값이 제공되므로 기본 생성자와 멤버와이즈 생성자가 자동으로 제공된다
- 확장에서 두 가지 새로운 생성자를 추가하였다
• init(area:): 면적을 사용하여 밑변과 높이를 계산하여 초기화
• init(copyFrom:): 기존의 삼각형을 복제하여 새로운 인스턴스를 생성
- 확장에서 멤버와이즈 생성자를 호출하는 방식으로 구현하였다 (
self.init())
- 확장에서 정의된 생성자와 기존의 기본 생성자 및 멤버와이즈 생성자를 모두 사용할 수 있다
클래스 - 생성자 확장의 예시 (예시: Person)
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let person = Person(name: "Alice", age: 30)
extension Person {
convenience init(name: String) {
self.init(name: name, age: 0)
}
convenience init(json: [String: Any]) {
let name = json["name"] as? String ?? "Unknown"
let age = json["age"] as? Int ?? 0
self.init(name: name, age: age)
}
}
let personByName = Person(name: "Bob")
let personByJSON = Person(json: ["name": "Charlie", "age": 25])
print("Person 1 - Name: \(personByName.name), Age: \(personByName.age)")
print("Person 2 - Name: \(personByJSON.name), Age: \(personByJSON.age)")
Person 클래스는 이름과 나이를 가진다
- 지정 생성자는 기존 방식으로 정의되었다
- 확장에서 두 가지 편의 생성자를 추가하였다
• init(name:): 이름만 설정하여 나이를 0으로 초기화
• init(json:): JSON 데이터를 사용하여 인스턴스를 생성 (예: 서버로부터 받은 데이터)
- 확장에서 추가된 생성자도 기존의 지정 생성자와 함께 사용할 수 있다
요약
- 조체는 확장을 사용하여 지정 생성자도 추가할 수 있다 (본체에서 생성자를 정의하지 않은 경우)
- 클래스는 확장에서 편의 생성자만 추가할 수 있다 (지정 생성자는 추가 불가능)
- 확장에서 정의된 생성자는 기존의 기본 생성자 및 멤버와이즈 생성자와 함께 사용할 수 있다 (구조체)
- 확장은 기존 타입을 수정하지 않고도 생성자를 추가할 수 있는 강력한 도구이다