[Swift] 익스텐션 (Extension)

김형근·2024년 7월 23일

[Swift] 문법

목록 보기
18/20

🍎 [Swift] 익스텐션 (Extension)

  • 익스텐션은 구조체, 클래스, 열거형, 프로토콜 타입에 새로운 기능을 추가할 수 있는 기능입니다.
  • 기능을 추가하려는 타입의 구현된 소스 코드를 알지 못하거나 볼 수 없다 해도, 타입만 알고 있다면 그 타입의 기능을 확장할 수 있습니다.

익스텐션으로 추가할 수 있는 기능.

  • 연산 타입 프로퍼티
  • 연산 인스턴스 프로퍼티
  • 타입 메서드
  • 인스턴스 메서드
  • 이니셜라이저
  • 서브스크립트
  • 중첩타입
  • 특정 프로토콜을 준수할 수 있도록 기능 추가

    단, 기존에 존재하는 기능을 재정의할 수는 없습니다.


🍏 클래스의 상속과 익스텐션 비교

  • 클래스의 상속: 클래스 타입에서만 가능하며, 특정 타입을 물려받아 하나의 새로운 타입을 정의하고 추가 기능을 구현하는 수직 확장입니다.

  • 익스텐션: 구조체, 클래스, 프로토콜 등에 적용할 수 있으며, 기존의 타입에 기능을 추가하는 수평 확장입니다. 상속과는 달리 기존 기능을 재정의할 수 없습니다.


🍏 익스텐션 활용

요약: 익스텐션은 외부 라이브러리나 프레임워크에서 가져온 타입에 기능을 추가할 때 유용합니다. 모든 타입에 연산 프로퍼티, 메서드, 이니셜라이저, 서브스크립트, 중첩 데이터 타입 등을 추가할 수 있습니다. 특히, 프로토콜과 함께 사용하면 강력한 기능을 제공합니다.

익스텐션을 사용하는 대신 원래 타입을 정의한 소스에 기능을 추가하는 방법도 있겠지만, 외부 라이브러리나 프레임워크를 가져다 썼다면 원본 소스를 수정하지 못합니다. 이처럼 외부에서 가져온 타입에 내가 원하는 기능을 추가하고자 할 때 익스텐션을 사용합니다. 상속을 받지 않아도 되며, 구조체와 열거형에도 기능을 추가할 수 있으므로 익스텐션은 매우 편리한 기능입니다.

익스텐션은 모든 타입에 적용할 수 있습니다. 모든 타입이라 함은 구조체, 열거형, 클래스, 프로토콜, 제네릭 타입 등을 뜻합니다. 즉, 익스텐션을 통해 모든 타입에 연산 프로퍼티, 메서드, 이니셜라이저, 서브스크립트, 중첩 데이터 타입 등을 추가할 수 있습니다. 더불어 익스텐션은 프로토콜과 함께 사용하면 매우 강력한 기능을 선사합니다. 이 부분과 관련해 프로토콜 중심 프로그래밍(Protocol Oriented Programming)에 대해 더 알아보는 것을 추천합니다.


🍏 익스텐션 정의 문법

  • 익스텐션은 'extension' 키워드를 사용하여 정의합니다.
  • 익스텐션은 기존에 존재하는 타입에 새로운 기능을 추가할 때 사용합니다.
extension 확장할 타입 이름 {
    /* 타입에 추가될 새로운 기능 구현 */
}
  • 익스텐션은 기존에 존재하는 타입이 추가적으로 다른 프로토콜을 채택할 수 있도록 확장 할 수도 있습니다.
extension 확장할 타입 이름: 프로토콜1, 프로토콜2, 프로토콜3 ... {
    /* 프로토콜 요구사항 구현 */
}

🍏 익스텐션 구현

🧃 연산 프로퍼티 추가

  • 아래 익스텐션은 Int 타입에 두 개의 연산 프로퍼티를 추가한 것입니다. Int 타입의 인스턴스가 홀수인지 짝수인지 판별하여 Bool 타입으로 알려주는 연산 프로퍼티입니다. 익스텐션으로 Int 타입에 추가해준 연산 프로퍼티는 Int 타입의 어떤 인스턴스에도 사용이 가능합니다.
extension Int {
    // 짝수 여부를 확인하는 연산 프로퍼티
    var isEven: Bool {
        return self % 2 == 0
    }
    
    // 홀수 여부를 확인하는 연산 프로퍼티
    var isOdd: Bool {
        return self % 2 == 1
    }
}

print(1.isEven) // false
print(2.isEven) // true
print(1.isOdd) // true
print(2.isOdd) // false

var number: Int = 3
print(number.isEven) // false
print(number.isOdd) // true

number = 2
print(number.isEven) // true
print(number.isOdd) // false

🧃 메서드 추가

  • 아래 익스텐션을 통해 Int 타입에 인스턴스 메서드인 multiply(by:) 메서드를 추가했습니다. 여러 기능을 여러 익스텐션 블록으로 나눠서 구현해도 전혀 문제가 없습니다. 관련된 기능별로 하나의 익스텐션 블록에 묶어주는 것도 좋습니다.
extension Int {
    // 특정 숫자와 곱하는 메서드
    func multiply(by n: Int) -> Int {
        return self * n
    }
}

print(3.multiply(by: 2)) // 6
print(4.multiply(by: 5)) // 20

var number = 3
print(number.multiply(by: 2)) // 6
print(number.multiply(by: 3)) // 9

🧃 이니셜라이저 추가

  • 인스턴스를 초기화할 때 다양한 데이터를 전달받을 수 있도록 여러 종류의 이니셜라이저를 만들 수 있습니다. 타입의 정의부에 이니셜라이저를 추가하지 않더라도 익스텐션을 통해 이니셜라이저를 추가할 수 있습니다. 익스텐션으로 클래스 타입에 편의 이니셜라이저는 추가할 수 있지만, 지정 이니셜라이저는 추가할 수 없습니다. 지정 이니셜라이저와 디이니셜라이저는 반드시 클래스 타입의 구현부에 위치해야 합니다(값 타입은 상관없습니다).
extension String {
    // Int 타입 숫자를 String으로 초기화하는 이니셜라이저
    init(intTypeNumber: Int) {
        self = "\(intTypeNumber)"
    }
    
    // Double 타입 숫자를 String으로 초기화하는 이니셜라이저
    init(doubleTypeNumber: Double) {
        self = "\(doubleTypeNumber)"
    }
}

let stringFromInt: String = String(intTypeNumber: 100) // "100"
let stringFromDouble: String = String(doubleTypeNumber: 100.0) // "100.0"

익스텐션을 활용하면 다양하고 강력한 기능을 구현할 수 있지만, 해당 타입에 적합한 익스텐션을 구현하도록 주의해야 합니다.

profile
꾸준히 기록하기

0개의 댓글