大器晩成

[Extensions] 생성자의 확장 본문

iOS/Swift 문법

[Extensions] 생성자의 확장

zerobugpark 2024. 12. 26. 10:52

 [클래스]

  • 편의 생성자만 추가 가능합니다 (즉, 본체의 지정생성자를 호출하는 방법으로만 구현 가능) 
  • 지정생성자 추가 불가 / 소멸자 추가 불가합니다. (항상 본래의 클래스에서 정의해야 함)
  • 클래스의 경우 상우의 지정생성자를 호출하는 델리게이트 어크로스가 발생하기 때문에, 편의생성자만 호출 가능합니다.

*델리게이트 어크로스: 자신의 지정생성자를 호출하는 것

 

클래스 - 생성자 확장의 예시

// UIColor 기본 생성자
//UIColor(red: <CGFloat>, green: <CGFloat>, blue: <CGFloat>, alpha: <CGFloat>)
var color = UIColor(red: 0.3, green: 0.5, blue: 0.4, alpha: 1)
    
// 익스텐션 + 편의생성자 조합
extension UIColor {      
    
    convenience init(color: CGFloat) {   // CGFloat = Core Graphics Float
        self.init(red: color/255, green: color/255, blue: color/255, alpha: 1)
    } //편의 생성자 구현 후 본체의 지정 생성자 호출

}


//쉽게 객체 생성하는 방법을 제공 가능해집니다
UIColor(color: 1)
  • 편의생성자로 생성 후 본체의 지정생성자 호출

 

 

  [구조체]

  • 구조체는 (원래) 편의 생성자가 존재하지 않고, 상속과 관련이 없기 때문에  지정생성자의 형태로도 (자유롭게) 생성자 구현 가능합니다.
  • (1) (편의 생성자와 비슷한) 생성자를 추가하여 본체의 지정 생성자를 호출하는 방법으로도 구현 가능합니다.
  • (2) 새롭게 지정생성자 형태로 구현하는 것도 가능

 

  [구조체 참고 사항]

  • (본체) 직접 생성자 구현하면, 기본 생성자 init() /멤버와이즈 생성자 제공 안 되는 것이 원칙입니다.
  • (본체) 모든 저장속성에 기본값제공 + (본체에 직접) 생성자를 구현하지 않았다면, 확정에서 생성자를 정의해도 기본생성자, 멤버와이즈 생성자가 제공됩니다.
  • (즉, 확장에서 생성자를 구현해도, 본체에는 여전히 기본 생성자/멤버와이즈 생성자가 자동 제공 되고 본체의 기본 생성자/멤버와이즈 생성자 호출하는 방식으로의 구현도 가능합니다.)

 

구조체 - 생성자 확장의 예시

 

구조체는 편의생성자를 제공하지 않는다.

# 구조체는 편의생성자를 제공하지 않는다.
struct Point {
    var x = 0.0, y = 0.0
    
    init() { 
        self.init(x: 0.0, y: 0.0)
    }
    
    init(x: Double, y: Double){
        self.x = x
        self.y = y
    }
    
}
  • 편의생성자를 제공하지는 않지만,  self.init을 호출함으로 편의생성자처럼 동작할 수 있게 만들 수 있습니다.

생성자를 추가하여 본체의 지정 생성자를 호출하는 방법으로 구현 

#1. 생성자를 추가하여 본체의 지정 생성자를 호출하는 방법으로 구현 
struct Point {
    var x = 0.0, y = 0.0
    
    init(x: Double = 0.0, y: Double = 0.0) {
        self.x = x
        self.y = y
    }
    //init(x: Double = 0.0, y: Double = 0.0) // 생성자 미 생성시 기본으로 제공
    //init() // 생성자 미 생성시 기본으로 제공
    
}


extension Point {
    init() {
        self.init(x: 0.0, y: 0.0)
    }
}

#2. 오류 발생 코드
struct Point {
    var x = 0.0, y = 0.0
}


extension Point {
    init() {
        self.init(x: 0.0, y: 0.0)
    }
    // init(num: Double) {
    //    self.init(x: num, y: num)  //에러 방지
    //}
}
  • 만약 구조체에 지정생성자가 만들어져 있지 않으면, 확장에서 생성자를 추가할 수 없습니다.
  • 구조체는 생성자를 구현하지 않으면 기본적으로 기본생성자와, 멤버와이즈 이니셜라이즈를 제공하기 때문에, 두 번 선언되었다는 오류가 발생합니다.

확장에서 본체의 지정생성자 호출

#1. 확장에서 본체의 지정생성자 호출

struct Point {
    var x = 0.0, y = 0.0

    init(x: Double, y: Double){
        self.x = x
        self.y = y
    }
}


extension Point {
    
    init() {
        self.init(x: 0.0, y: 0.0) // 확장의 생성자에서 본체의 지정생성자 호출
    }
}

 

모든 저장속성에 기본값이 있고, 본체의 생성자를 구현하지 않았을 때,

#1 모든 저장속성에 기본값이 있고, 본체의 생성자를 구현하지 않았을 때,
struct Point {
    var x = 0.0, y = 0.0
    // 생성자 미 생성시 기본으로 제공
    //init(x: Double = 0.0, y: Double = 0.0)
    //init()
}


extension Point {
    init(num: Double){
        self.x = num  // 생성자를 직접 구현해도 되고
        self.y = num
        //self.init(x = num, y = num) // 본체의 지정생성자를 호출해도 된다.
    }
}

let a = Point()
let b = Point(num: 10.0)
let c = Point(x: 20.0, y: 30.0)
  • 구조체에 확장에서 생성자를 추가할 경우, 기본생성자를 제공하는 구초제의 성격은 남아있어서, 기본생성자, 멤버와이즈 생성자, 확장에서 만든 생성자까지 모두 제공합니다.

 

 

 

애플 공식 예제

// 포인트 구조체
struct Point {
    var x = 0.0, y = 0.0

}

// 사이즈 구조체
struct Size {
    var width = 0.0, height = 0.0
}

// Rect구조체

struct Rect {     // 기본값 제공/생성자 구현안함  ===> 기본 생성자 / 멤버와이즈 생성자가 자동 제공 중
    var origin = Point()
    var size = Size()
}

let defaultRect = Rect()    // 기본생성자

//Rect(origin: Point(x: <Double>, y: <Double>), size: Size(width: <Double>, height: <Double>))

let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
                          size: Size(width: 5.0, height: 5.0))    // 멤버와이즈 생성자
                          
extension Rect {
    // 센터값으로 Rect 생성하는 생성자 만들기
    // 예외적인 경우 (저장속성에 기본값 + 본체에 생성자 구현 안한 경우, 여전히 기본생성자/멤버와이즈 생성자 제공)
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        
        // (1) 본체의 멤버와이즈 생성자 호출 방식으로 구현 가능
        self.init(origin: Point(x: originX, y: originY), size: size)
        
        // (2) 직접 값을 설정하는 방식으로도 구현 가능
        //self.origin = Point(x: originX, y: originY)
        //self.size = size
    }
}


// 새로 추가한 생성자로 인스턴스 생성해보기

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                      size: Size(width: 3.0, height: 3.0))
728x90