TIL: 확장(Extensions)의 개념

Royce·2025년 3월 23일

Swift 문법

목록 보기
41/63

확장(Extensions)

  • 확장은 기존의 타입(클래스, 구조체, 열거형, 프로토콜)에 새로운 기능을 추가하는 개념이다
  • 상속과는 다르게 기존 타입의 코드를 변경하지 않고, 새로운 기능을 추가하는 방식이다

상속과 확장의 차이

상속 (Inheritance)

  • 수직적인 개념으로 기존 타입을 상속받아 새로운 타입을 정의한다
  • 기존 타입의 속성과 메서드를 물려받아 새로 정의하거나, 기존 메서드를 재정의(Override)할 수 있다
  • 기존 타입의 구조를 확장하면서도 기존 기능을 변경할 수 있다
  • 예) Person 클래스를 상속하여 Student 클래스를 만들고, 메서드를 재정의하거나 새로운 속성을 추가한다

확장 (Extension)

  • 수평적인 개념으로 기존 타입에 새로운 기능을 추가한다
  • 기존 기능을 재정의(Override)할 수 없고, 새로운 기능을 추가하는 것만 가능하다
  • 기존의 타입을 수정하지 않고도 기능을 확장할 수 있는 강력한 기능이다
  • 예) Int 타입에 새로운 기능을 추가하거나, 기존 클래스에 새로운 메서드를 추가한다
  • 확장에서 구현한 메서드는 기본적으로 재정의가 불가능하다 (하지만 @objc를 붙이면 가능)

확장 문법 (Extension Syntax)

// 기존 타입 정의
struct Calculator {
    var value: Int
}

// 기존 타입을 확장하여 새로운 기능 추가
extension Calculator {
    func squared() -> Int {
        return value * value
    }
    
    func cubed() -> Int {
        return value * value * value
    }
}

// 사용 예시
let calculator = Calculator(value: 3)
print(calculator.squared())  // 출력: 9
print(calculator.cubed())    // 출력: 27
  • Calculator 구조체는 value라는 저장 속성을 가진다
  • 확장을 사용하여 Calculator 타입에 squared()cubed() 메서드를 추가
  • 기존의 Calculator 인스턴스에서도 새로 추가된 메서드를 사용할 수 있다
  • 확장은 기존 타입을 수정하지 않고도 기능을 확장할 수 있는 방법을 제공한다

예시를 통한 상속과 확장의 차이 이해

// 기존 클래스 정의
class Animal {
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    func sound() -> String {
        return "동물 소리"
    }
}

// Animal 클래스를 상속하여 새로운 클래스 정의
class Dog: Animal {
    var breed: String
    
    init(name: String, breed: String) {
        self.breed = breed
        super.init(name: name)
    }
    
    override func sound() -> String {   // 기존 기능을 재정의 (Override)
        return "멍멍"
    }
}

// Dog 클래스에 확장을 사용하여 새로운 기능 추가
extension Dog {
    func run() -> String {
        return "\(name)가 달린다."
    }
}

// 사용 예시
let myDog = Dog(name: "바둑이", breed: "진돗개")
print(myDog.sound())  // 출력: 멍멍 (재정의된 메서드)
print(myDog.run())    // 출력: 바둑이가 달린다. (확장을 통해 추가된 메서드)
  • Animal 클래스는 모든 동물의 공통 특성인 namesound() 메서드를 정의
  • Dog 클래스는 Animal 클래스를 상속받아 breed 속성을 추가하고, sound() 메서드를 재정의
  • 상속을 사용하여 기존 기능을 수정하고 확장할 수 있는 점을 보여준다
  • 확장을 사용하여 Dog 클래스에 run() 메서드를 추가 (새로운 기능만 추가 가능)
  • 기존의 Dog 인스턴스에서도 새롭게 추가된 기능을 사용할 수 있다

확장에서 구현한 메서드 재정의 가능 여부 (@objc 사용)

// 기존 클래스 정의
class Student {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

// 확장을 사용하여 메서드 추가
extension Student {
    @objc func study() {
        print("\(name)이 공부한다.")
    }
}

// Student 클래스를 상속하여 새로운 클래스 정의
class CollegeStudent: Student {
    override func study() {    // @objc를 사용했기 때문에 재정의 가능
        print("\(name)이 대학 공부를 한다.")
    }
}

// 사용 예시
let student = CollegeStudent(name: "철수")
student.study()  // 출력: 철수이 대학 공부를 한다.
  • 확장에서 구현된 메서드는 기본적으로 재정의할 수 없다
  • 하지만 메서드 정의에 @objc를 추가하면 재정의가 가능해진다 (Objective-C 런타임과 호환되기 때문)
  • 이 방식은 주로 클래스 타입에서만 사용된다 (구조체나 열거형에서는 불가능)

확장에서 추가 가능한 멤버의 종류

  • (타입) 계산 속성, (인스턴스) 계산 속성
  • (타입) 메서드, (인스턴스) 메서드
  • 새로운 생성자 (클래스의 경우, 편의생성자만 추가 가능)
  • 서브스크립트 (subscript)
  • 새로운 중첩 타입 (enum, struct 등)
  • 프로토콜 채택 및 관련 메서드 구현

지정생성자 및 확장에서의 제약사항

  • 확장에서는 지정생성자와 소멸자를 정의할 수 없다
  • 지정생성자는 반드시 본체에서 정의해야 하며, 확장에서 정의하면 컴파일 에러가 발생한다
  • 확장에서는 오직 편의생성자만 추가할 수 있다 (클래스의 초기화를 간편하게 만들어주는 생성자)

요약

  • 확장은 기존 타입을 수정하지 않고도 기능을 추가할 수 있는 수평적인 개념이다
  • 기존 타입에 새로운 기능(메서드, 계산 속성 등)을 추가할 수 있지만, 기존 메서드를 재정의할 수 없다
  • 상속은 기존 타입을 기반으로 새로운 타입을 만들고 기존 기능을 재정의(Override)할 수 있는 수직적인 개념이다
  • 기본 타입 (Int, String, 등)도 확장을 통해 기능을 추가할 수 있다 (소급 모델링)
  • 지정생성자 및 소멸자는 확장에서 정의할 수 없고, 저장 속성도 추가할 수 없다
  • 확장에서 구현된 메서드를 재정의하려면 @objc를 사용해야 한다
profile
iOS 개발자 지망생

0개의 댓글