[Swift 공식문서 읽기]Extensions

llim🧚🏻‍♀️·2021년 8월 24일
0

Swift

목록 보기
20/26
post-thumbnail

안녕하세요. 엘림입니다🙇🏻‍♀️

Swift 공식 문서를 정독하기 시리즈입니다!

제 스타일대로 정리했으니 추가적으로 더 필요한 정보는
공식문서 링크를 눌러 확인해주세용!

좀 더 편하게 보기위해 한국어로 번역된 사이트를 함께 확인했습니다!ㅎㅎ

자, 그럼 시작해볼까요

이 글은 공부하면서 작성한 글이기 때문에 잘못된 정보가 있을 수 있습니다.🥺
금방 잊어버릴... 미래의 저에게 다시 알려주기 위한 글이다보니
혹시라도 틀린 부분이 있다면, 댓글로 친절하게 알려주시길 부탁드립니다.🙏


익스텐션

익스텐션을 이용해 클래스, 구조체, 열거형 혹은 프로토콜 타입에 기능을 추가할 수 있습니다. 원본 코드를 몰라도 그 타입에 대한 기능을 확장할 수 있습니다.
익스텐션을 정의하여 존재하는 타입에 새 기능을 추가하면, 그 기능은 익스텐션을 정의하기 이전에 생성한 인스턴스를 포함한 존재하는 모든 해당 타입의 인스턴스에서 사용 가능합니다.
하나의 익스텐션에서 현재 존재하는 타입에 한개 이상의 프로토콜을 따르도록 확장할 수 있습니다.

  • 연산 프로퍼티(인스턴스, 타입 모두) 추가
  • 메소드(인스턴스, 타입 모두) 추가
  • 새로운 이니셜라이저 생성
  • 서브스크립트 정의
  • 중첩 타입의 선언과 사용
  • 특정 프로토콜을 따르는 타입 만들기
    (단, 익스텐션은 타입에 새 기능을 추가할 수는 있지만 오버라이드는 할 수 없습니다.)

연산 프로퍼티

익스텐션은 새 연산 프로퍼티를 추가할 수 있지만, 저장 프로퍼티나 프로퍼티 옵저버를 추가할 수는 없습니다.

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"

let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// Prints "A marathon is 42195.0 meters long"

이니셜라이저

익스텐션으로 클래스에 새로운 편리한 이니셜라이저(convenience initializer)를 추가할 수는 있지만, 지정된 이니셜라이저(designated initializers)나 디이니셜라이저(deinitializers)를 추가할 수는 없습니다.
지정된 이니셜라이저는 항상 반드시 오리지널 클래스의 구현에서 작성되어야 합니다.

만약 익스텐션으로 값타입에 이니셜라이저를 추가했고, 그 값타입이 모든 프로퍼테에 대해 기본 값을 제공하면서 커스텀 이니셜라이저를 정의하지 않았다면, 기본 이니셜라이저와 멤버쪽 이니셜라이저를 호출할 수 있습니다.
(값 타입의 오리지널 구현 부분에서 이니셜라이저 코드를 작성했다면, 이 경우에 해당하지 않습니다.)

만약 다른 모듈에 선언되어 있는 구조체에 이니셜라이저를 추가하는 익스텐션을 사용한다면, 새로운 이니셜라이저는 모듈에 정의된 이니셜라이저를 호출하기 전까지 self에 접근할 수 없습니다.

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()
}

extension Rect {
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
//        self.origin = center // error
//        self.size = size // error 생성되기 전에 self 접근 안됨
        self.init(origin: Point(x: originX, y: originY), size: size)
//        self.size = size // 가능!
    }
}

let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
   size: Size(width: 5.0, height: 5.0))
   
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)

메소드

익스텐션을 이용해 존재하는 타입에 인스턴스 메소드나, 타입 메소드를 추가할 수 있습니다.

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

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

익스텐션에서 추가된 인스턴스 메소드도 자신(self)를 변경할 수 있습니다. 값 타입(구조체, 열거형)에서는 보통의 값 타입과 마찬가지로 mutating 키워드를 붙여야 합니다.

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

서브스크립트

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
746381295[9]
// 9로 처리할 수 있는 자릿 수를 넘어가면 0을 반환
0746381295[9]

중첩 타입

extension 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
        }
    }
}

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 + "

오늘도 스위프트 공식문서를 정리해보았군욥~
다음편도 힘내보겠습니다!

감사합니다🙇🏻‍♀️

profile
한달 차 iOS 개발자입니다🐥

0개의 댓글