티스토리 뷰

익스텐션을 이용하면 클래스, 구조체, 열거형 혹은 프로토콜 타입에 기능을 추가할 수 있다. retroactive modeling으로 알려진 것과 같이 원본 코드를 몰라도 그 타입에 대한 기능을 확장할 수 있다. 

 

swift에서 익스텐션을 이용해 다음과 같은 일들을 할 수 있다.

 

 1) 계산된 인스턴스 프로퍼티와 계산된 타입 프로퍼티의 추가

 2) 인스턴스 메서드와 타입 메서드의 추가

 3) 새로운 이니셜라이저 제공

 4) 서브스크립트의 정의

 5) 중첩 타입의 선언과 사용

 6) 특정 프로토콜을 따르는 타입을 만들기


1. 익스텐션 문법

익스텐션은 extension 키워드를 사용하여 선언한다.

extension SomeType {
    // new functionality to add to SomeType goes here
}

 

하나의 익스텐션에서 현재 존재하는 타입에 한개 이상의 프로토콜을 따르도록 확장할 수도 있다.

extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
}

2. 계산된 프로퍼티

익스텐션을 아용하여 존재하는 타입에 계산된 인스턴스 프로퍼티와 타입 프로퍼티를 추가할 수 있다. 

 

아래 예제는 Swift의 Built-in 타입인 Double에 5개의 계산된 인스턴스 프로퍼티를 추가하는 예제이다.

extension Double {
    var km: Double {return self * 1_000.0}
    var m: Double { return self}
    var cm: Double { return self / 100.0}
    var mm: Double {return self / 1_000.0}
    var ft: Double { return self / 3.28084}
}

let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
// Prints "One inch is 0.0254 meters"
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
// Prints "Three feet is 0.914399970739201 meters"

3. 이니셜라이저

익스텐션을 이용하면 존재하는 타입에 새로운 이니셜라이저를 추가할 수 있다. 이 방법으로 커스텀 타입의 이니셜라이저 파라미터를 넣을 수 있도록 변경하거나 원래 구현에서 포함되지 않는 초기화 정보를 추가할 수 있다.

 

단, 익스텐션은 클래스에 Convenience 이니셜라이저만 새로 추가할 수 있을 뿐, designated 이니셜라이저나 디이니셜라이저는 추가할 수 없으며, designated 이니셜라이저는 항상 반드시 오리지널 클래스의 구현에서 작성되어야 한다.

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
}

위 예제에서는 size와 Point 구조체를 정의하고 그것을 사용하는 Rect 구조체를 정의했다. Rect 구조체에서 모든 프로퍼티의 기본 값을 제공하기 때문에 Rect 구조체는 아래와 같이 기본 이니셜라이저와 멤버 쪽 이니셜라이저를 자동으로 제공받아 사용할 수 있다.

extension Rect {
    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)
    }
}
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                      size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

4. 메서드

익스텐션을 이용하여 존재하는 타입에 인스턴스 메서드나 타입 메서드를 추가할 수 있다. 

extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}

3.repetitions {
    print("Hello!")
}
// Hello!
// Hello!
// Hello!

5. 변경 가능한 인스턴스 메서드

mutating 키워드를 사용하면 참조 타입으로 원본 주소 값의 데이터를 변경할 수 있다.

extension Int {
    mutating func square() {
        self = self * self
    }
}
var someInt = 3
someInt.square()
// someInt is now 9

6. 서브스크립트

서브스크립트도 당연하게 익스텐션을 사용하여 새로 추가할 수 있다.

extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex {
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
        // 10 * n번째 수로 현재 수를 나눈 것의 나머지
      // 1인 경우 746381295 % 10 -> 5가 나머지
      // 2인 경우 746381295 % 10 -> 9가 나머지
    }
}
746381295[0]
// returns 5
746381295[1]
// returns 9
746381295[2]
// returns 2
746381295[8]
// returns 7
Comments