안녕하세요 iOS 개발자 워너비 루크입니다
오늘은 Swift 공식 문서의 Extensions 부분에 대해서 공부해보려고 합니다.
Extensions
Extension(익스텐션)은 기존의 클래스, 구조체, 열거형, 프로토콜들에 새로운 기능을 추가하는 데 사용됩니다.
원본 소스코드에 대한 접근이 허용되지 않은 타입에 또한 기능의 확장이 가능해집니다.
익스텐션이 제공하는 기능은 아래와 같습니다.
•
계산 프로퍼티, 계산 타입 프로퍼티 추가
•
인스턴스, 타입 메서드 추가
•
새로운 initializer 추가
•
subscript 정의
•
새로운 중첩 타입 정의
•
이미 존재하는 타입이 프로토콜을 준수하도록 만들기
프로토콜의 요구조건 또한 확장이 가능합니다.
extension 은 새로운 기능을 추가만 가능할 뿐, override 하지 않습니다.
Extension Syntax
extension SomeType {
// new functionality to add to SomeType goes here
}
Swift
복사
익스텐션을 사용하면 기존의 클래스에 추가적인 프로토콜을 채택시킬 수 있습니다. 프로토콜의 추가는 기존 클래스에 프로토콜을 채택하는 방법과 동일합니다.
extension SomeType: SomeProtocol, AnotherProtocol {
// implementation of protocol requirements goes here
}
Swift
복사
Computed Properties
익스텐션을 활용하면 기존의 타입에 컴퓨티드 프로퍼티와 컴퓨티드 타입 프로퍼티를 추가로 정의할 수 있습니다.
아래는 Swift 의 내장 타입인 Double 에 계산 프로퍼티를 추가한 예제입니다
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"
Swift
복사
위에서 추가된 계산 프로퍼티들은 여러가지 길이 단위를 표현합니다. 계산 프로퍼티로 구현되었으나, 이렇게 추가된 프로퍼티들은 리터럴 값에 사용이 가능합니다.
이러한 프로퍼티들은 read-only 인 계산 프로퍼티임을 명심합시다.
따라서 get 키워드의 생략이 가능합니다
리턴값이 Double 이므로 리턴 값을 수학적인 계산에 사용이 가능합니다.
let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// Prints "A marathon is 42195.0 meters long"
Swift
복사
익스텐션으로는 다음 기능들을 추가할 수 없습니다.
•
stored property
•
property observer
Initializers
기존 타입에 새 생성자를 추가할 수 있습니다.
커스텀 타입을 활용한 새로운 생성자 추가가 가능합니다!
새 convenience 생성자를 class 에 추가할 수 있습니다.
새 desiganated 생성자 또는 deinitializer 는 추가할 수 없습니다.
designated 생성자 와 deinitializer 는 반드시 클래스 원본에 정의 되어야합니다.
만약 value 타입에 새 생성자를 추가하는 경우, 새 생성자에서 모든 스토어드 프로퍼티에 초기값을 반드시 주어야합니다.
새로이 추가한 생성자 내부에서 기존 생성자를 호출할 수 있습니다.
단 커스텀 생성자는 ㄴ호출이 불가능합니다.
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()
}
Swift
복사
위 예시에서 Rect 구조체는 모든 프로퍼티에 대한 초기값을 제공했으므로,
자동으로 기본 생성자를 사용할 수 있습니다.
let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
Swift
복사
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)
}
}
Swift
복사
위 예시에서 기본 생성자를 호출하는 모습을 확인할 수 있습니다.
Methods
익스텐션들은 새 인스턴스 메서드를 추가할 수 있습니다.
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
}
3.repetitions {
print("Hello!")
}
// Hello!
// Hello!
// Hello!
Swift
복사
위는 Int 타입에 새로운 메서드를 추가한 예시입니다.
Mutating Instance Methods
인스턴스 자기 자신을 변경하는 메서드를 extension 에 선언할 수 있습니다.
self 를 변경하는 구조체와 열거형 메서드들은 mutating 이라는 키워드를 앞에 작성해주어야 합니다.
extension Int {
mutating func square() {
self = self * self
}
}
var someInt = 3
someInt.square()
// someInt is now 9
Swift
복사
Subscripts
extension을 사용해 존재하는 타입에 새 subscript 를 추가할 수 있습니다.
extension 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
Swift
복사
만약 Int 값이 인덱스에 해당하는 자리수 를 가지지 못한다면, 0 을 리턴하게 된다.
Nested Types
extension 을 활용하면 이미 존재하는 클래스, 구조체, 열거형에 중첩 타입을 추가할 수 있습니다.
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
}
}
}
Swift
복사
위 예제에서는 Int 형에 새 중첩 열거형을 추가했다.
이 열거형은 Kind 로 정수형의 종류를 표현한다. ( 음수, 0 , 양수 )
이 예시는 또한 kind 라는 새 계산 인스턴스 프로퍼티를 추가한다.
이렇게 추가된 열거형은 정수의 적절한 Kind 열거형 case를 리턴한다.
이렇게 정의된 case 는 switch 문에 사용이 가능하다.
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 + "
Swift
복사