Extensions

Groot·2022년 10월 10일
0

Swift Language Guide

목록 보기
20/24
post-thumbnail
post-custom-banner

Extensions

  • Extensions은 기존 클래스, 구조, 열거 또는 프로토콜 유형에 새로운 기능을 추가합니다.
  • 여기에는 원본 소스 코드에 액세스할 수 없는 유형을 Extensions하는 기능이 포함됩니다(소급 모델링이라고 함).
  • Extensions은 Objective-C의 카테고리와 유사합니다. (Objective-C 카테고리와 달리 Swift Extensions에는 이름이 없습니다.)
  • Swift의 Extensions은 다음을 수행할 수 있습니다.
    • 계산된 인스턴스 속성 및 계산된 유형 속성 추가
    • 인스턴스 메소드 및 유형 메소드 정의
    • 새로운 이니셜라이저 제공
    • subscripts 정의
    • 새로운 중첩 유형 정의 및 사용
    • 기존 유형이 프로토콜을 따르도록 합니다.
  • Swift에서는 프로토콜을 Extensions하여 요구 사항의 구현을 제공하거나 준수하는 유형이 활용할 수 있는 추가 기능을 추가할 수도 있습니다.

    Extensions은 유형에 새로운 기능을 추가할 수 있지만 기존 기능을 재정의할 수는 없습니다.

📌 Extensions Syntax

  • Extensions 키워드를 사용하여 Extensions을 선언합니다.
    Extensions SomeType {
        // new functionality to add to SomeType goes here
    }
  • Extensions은 하나 이상의 프로토콜을 채택하도록 기존 유형을 Extensions할 수 있습니다.
  • 프로토콜 적합성을 추가하려면 클래스 또는 구조에 대해 작성하는 것과 동일한 방식으로 프로토콜 이름을 작성합니다.
    Extensions SomeType: SomeProtocol, AnotherProtocol {
        // implementation of protocol requirements goes here
    }
  • 이러한 방식으로 프로토콜 적합성을 추가하는 것은 Extensions을 사용하여 프로토콜 적합성 추가에 설명되어 있습니다.
  • 제네릭 유형 Extensions에 설명된 대로 Extensions을 사용하여 기존 제네릭 유형을 Extensions할 수 있습니다.
  • 일반 Where 절이 있는 Extensions에 설명된 대로 일반 유형을 Extensions하여 기능을 조건부로 추가할 수도 있습니다.

    기존 유형에 새 기능을 추가하기 위해 Extensions을 정의하면 Extensions이 정의되기 전에 생성된 경우에도 해당 유형의 모든 기존 인스턴스에서 새 기능을 사용할 수 있습니다.

📌 Computed Properties

  • Extensions은 기존 유형에 computed instance properties와 계산된 유형 속성을 추가할 수 있습니다.
  • 이 예제는 거리 단위 작업에 대한 기본 지원을 제공하기 위해 5개의 계산된 인스턴스 속성을 Swift의 내장 Double 유형에 추가합니다.
Extensions 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"
  • 이러한 computed properties은 Double 값이 특정 길이 단위로 간주되어야 함을 나타냅니다.
  • computed properties으로 구현되지만 이러한 속성의 이름은 리터럴 값을 사용하여 거리 변환을 수행하는 방법으로 점 구문을 사용하여 부동 소수점 리터럴 값에 추가할 수 있습니다.
  • 다른 단위는 미터로 측정된 값으로 표현하기 위해 약간의 변환이 필요합니다.
  • 1킬로미터는 1,000미터와 같으므로 km 계산 속성은 값에 1_000.00을 곱하여 미터로 표시되는 숫자로 변환합니다.
  • 마찬가지로 1미터에는 3.28084피트가 있으므로 ft 계산 속성은 기본 Double 값을 3.28084로 나누어 피트에서 미터로 변환합니다.
  • 이러한 속성은 읽기 전용 계산 속성이므로 간결성을 위해 get 키워드 없이 표현됩니다.
  • 반환 값은 Double 유형이며 Double이 허용되는 모든 수학적 계산 내에서 사용할 수 있습니다.
    let aMarathon = 42.km + 195.m
    print("A marathon is \(aMarathon) meters long")
    // Prints "A marathon is 42195.0 meters long"

    Extensions은 새로운 계산 속성을 추가할 수 있지만 저장 속성을 추가하거나 기존 속성에 속성 관찰자를 추가할 수 없습니다.

📌 Initializers

  • Extensions은 기존 유형에 새 초기화 프로그램을 추가할 수 있습니다.
  • 이를 통해 다른 유형을 Extensions하여 고유한 사용자 정의 유형을 초기화 매개변수로 허용하거나 유형의 원래 구현의 일부로 포함되지 않은 추가 초기화 옵션을 제공할 수 있습니다.
  • Extensions은 클래스에 새로운 편의 이니셜라이저를 추가할 수 있지만 클래스에 지정된 새 이니셜라이저 또는 디이니셜라이저를 추가할 수는 없습니다.
  • 지정된 이니셜라이저 및 디이니셜라이저는 항상 원래 클래스 구현에서 제공해야 합니다.
  • Extensions을 사용하여 모든 저장된 속성에 대한 기본값을 제공하고 사용자 정의 이니셜라이저를 정의하지 않는 값 유형에 이니셜라이저를 추가하는 경우 Extensions의 이니셜라이저 내에서 해당 값 유형에 대한 기본 이니셜라이저 및 멤버별 이니셜라이저를 호출할 수 있습니다.
  • 값 유형에 대한 이니셜라이저 위임에 설명된 대로 값 유형의 원래 구현의 일부로 이니셜라이저를 작성한 경우에는 그렇지 않습니다.
  • Extensions을 사용하여 다른 모듈에서 선언된 구조에 이니셜라이저를 추가하는 경우 새 이니셜라이저는 정의 모듈에서 이니셜라이저를 호출할 때까지 self에 액세스할 수 없습니다.
  • 아래 예제는 기하학적 사각형을 나타내는 사용자 지정 Rect 구조를 정의합니다.
  • 이 예제는 또한 모든 속성에 대해 기본값 0.0을 제공하는 Size 및 Point라는 두 가지 지원 구조를 정의합니다.
    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()
    }
  • Rect 구조체는 모든 속성에 대한 기본값을 제공하기 때문에 기본 이니셜라이저에 설명된 대로 기본 이니셜라이저와 멤버별 이니셜라이저를 자동으로 받습니다.
  • 다음 이니셜라이저는 새 Rect 인스턴스를 만드는 데 사용할 수 있습니다.
    let defaultRect = Rect()
    let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
       size: Size(width: 5.0, height: 5.0))
  • Rect 구조를 Extensions하여 특정 중심점과 크기를 취하는 추가 이니셜라이저를 제공할 수 있습니다.
    Extensions 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)
        }
    }
  • 이 새로운 이니셜라이저는 제공된 중심점과 크기 값을 기반으로 적절한 원점을 계산하는 것으로 시작합니다.
  • 그런 다음 이니셜라이저는 구조의 자동 멤버별 이니셜라이저 init(origin: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)

    새로운 이니셜라이저에 Extensions을 제공하는 경우 이니셜라이저가 완료되면 각 인스턴스가 완전히 초기화되었는지 확인해야 합니다.

📌 Methods

  • Extensions은 기존 유형에 새 인스턴스 메소드 및 유형 메소드를 추가할 수 있습니다.
  • 다음 예제에서는 Int 유형에 반복이라는 새 인스턴스 메서드를 추가합니다.
    Extensions Int {
        func repetitions(task: () -> Void) {
            for _ in 0..<self {
                task()
            }
        }
    }
  • repeats(task:) 메서드는 매개변수가 없고 값을 반환하지 않는 함수를 나타내는 () -> Void 유형의 단일 인수를 사용합니다.
  • 이 Extensions을 정의한 후에는 모든 정수에 대해 repeats(task:) 메서드를 호출하여 여러 번 작업을 수행할 수 있습니다.
    3.repetitions {
        print("Hello!")
    }
    // Hello!
    // Hello!
    // Hello!

📍 Mutating Instance Methods

  • Extensions으로 추가된 인스턴스 메서드는 인스턴스 자체를 수정(또는 변경)할 수도 있습니다.
  • self 또는 해당 속성을 수정하는 구조 및 메서드는 원래 구현에서 메서드를 변경하는 것처럼 인스턴스 메서드를 mutating으로 표시해야 합니다.
  • 아래 예제는 원래 값을 제곱하는 Square라는 새로운 변경 방법을 Swift의 Int 유형에 추가합니다.
    Extensions Int {
        mutating func square() {
            self = self * self
        }
    }
    var someInt = 3
    someInt.square()
    // someInt is now 9

📌 Subscripts

  • Extensions은 기존 유형에 새 첨자를 추가할 수 있습니다. 이 예제는 Swift의 내장 Int 유형에 정수 첨자를 추가합니다. 이 아래 첨자 [n]은 숫자 오른쪽에서 n자리의 십진수를 반환합니다.
  • 123456789[0] returns 9
  • 123456789[1] returns 8
    Extensions Int {
        subscript(digitIndex: Int) -> Int {
            var decimalBase = 1
            for _ in 0..<digitIndex {
                decimalBase *= 10
            }
            return (self / decimalBase) % 10
        }
    }
    746381295[0]
    // returns 5
    746381295[1]
    // returns 9
    746381295[2]
    // returns 2
    746381295[8]
    // returns 7
  • Int 값에 요청된 인덱스에 대한 충분한 자릿수가 없으면 아래 첨자 구현은 숫자가 왼쪽에 0으로 채워진 것처럼 0을 반환합니다.
    746381295[9]
    // returns 0, as if you had requested:
    0746381295[9]

📌 Nested Types

  • Extensions은 기존 클래스, 구조 및 열거형에 새로운 중첩 유형을 추가할 수 있습니다.
    Extensions Int {
        enum Kind {
            case negative, zero, positive
        }
        var kind: Kind {
            switch self {
            case 0:
                return .zero
            case let x where x > 0:
                return .positive
            default:
                return .negative
            }
        }
    }
  • 이 예제에서는 Int에 새 중첩 열거형을 추가합니다.
  • Kind라고 하는 이 열거형은 특정 정수가 나타내는 숫자의 종류를 나타냅니다.
  • 구체적으로 숫자가 음수인지 0인지 양수인지를 나타냅니다.
  • 이 예제는 또한 해당 정수에 대한 적절한 Kind 열거 케이스를 반환하는 종류라는 새로운 계산된 인스턴스 속성을 Int에 추가합니다.
  • 이제 모든 Int 값과 함께 중첩 열거를 사용할 수 있습니다.
    func printIntegerKinds(_ numbers: [Int]) {
        for number in numbers {
            switch number.kind {
            case .negative:
                print("- ", terminator: "")
            case .zero:
                print("0 ", terminator: "")
            case .positive:
                print("+ ", terminator: "")
            }
        }
        print("")
    }
    printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
    // Prints "+ + - 0 - 0 + "
  • 이 함수, printIntegerKinds(_:)는 Int 값의 입력 배열을 취하고 해당 값을 차례로 반복합니다.
  • 배열의 각 정수에 대해 함수는 해당 정수의 종류 계산 속성을 고려하고 적절한 설명을 인쇄합니다.

    number.kind는 이미 Int.Kind 유형으로 알려져 있습니다. 이 때문에 모든 Int.Kind 케이스 값은 Int.Kind.negative가 아닌 .negative와 같이 switch 문 내에서 축약 형식으로 작성할 수 있습니다.

profile
I Am Groot
post-custom-banner

0개의 댓글