확장이란 기존 클래스, 구조체, 또는 열거형 타입에 새로운 기능을 추가하는 것으로, 원본 타입에 접근하지 못하는 타입들도 확장하여 사용할 수 있다.
즉, 새로운 기능을 부여하여 사용할 수 있게 하는 것이다.
extension SomeType {
}
혹은
extension SomeType: SomeProtocol, AnotherProtocol {
}
채택하고자 하는 프로토콜을 추가할 수도 있다.
익스텐션은 타입에 새로운 기능을 추가할 수 있지만, 기존에 존재하는 기능을 재정의하는 것은 불가능하다. (override 불가)
→ 익스텐션은 클래스에 기능을 추가하는, 수평적으로 추가할 때 쓰이는 기능이며, override는 수직적인 상속에서 하기 때문에 재정의가 불가능하다.
extension Int {
var double: Int {
return self * 2
}
}
이렇게 연산 프로퍼티를 선언한다면
let number = 10
print(number.double) //20
이렇에 모든 Int 타입에서 사용 가능하다.
extension Int {
//타입 메서드
static func printZero() {
print(0)
}
//인스턴스 메서드
mutating func square() {
// 구조체(열거형)에서, 자신의 속성을 변경하는 메서드는 mutating 키워드가 필요
self = self * self
}
}
Int.printZero() // 0
var someInt = 3
someInt.square()
someInt // 9
extension String {
init(int: Int) {
self = "\(int)"
}
init(double: Double) {
self = "\(double)"
}
}
let stringFromInt: String = String(int: 100)
// "100"
let stringFromDouble: String = String(double: 100.0)
// "100.0"
인스턴스 초기화 시에도 초기화에 필요한 다양한 데이터를 받을 수 있도록 이니셜라이저를 만들 수 있다. 반드시 지정 이니셜라이저와 디이니셜라이저는 클래스 타입의 구현부에 위치해야 한다.
extension String {
subscript(idx: Int) -> String? {
guard (0..<count).contains(idx) else {
return nil
}
let target = index(startIndex, offsetBy: idx)
return String(self[target])
}
}
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
}
}
}
print(1.kind) //positive
print(0.kind) //zero
print((-1).kind) //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(numbers: [3, 20, -2, -31, 0, 2])
//+ + - - 0 +
참고자료
https://babbab2.tistory.com/124
https://yagom.github.io/swift_basic/contents/20_extension/
https://seons-dev.tistory.com/entry/Swift-%EA%B8%B0%EC%B4%88%EB%AC%B8%EB%B2%9543-Extensions