[Swift] 프로토콜 익스텐션 (Protocol Extension)

이자민·2025년 6월 25일

iOS

목록 보기
7/10

GQ1. Protocol Extension이 뭘까?
GQ2. 사용하면 뭐가 좋을까?

Description

개념

  • 프로토콜에 기본 구현을 제공하는 기능
정의 가능 항목설명예시 코드
메서드 (Method)프로토콜에서 선언된 함수의 기본 동작 제공func prepareForStudy() { ... }
계산 프로퍼티 (Computed Property)저장은 못하지만 계산 결과를 반환하는 프로퍼티 제공var motto: String { "Hello World" }
서브스크립트 (Subscript)특정 타입에 인덱싱 기능 제공subscript(index: Int) -> String { ... }
중첩 타입 (Nested Type)enum, struct, class 등 타입 내부 정의enum StudyStyle { case silent, handsOn }
제약 조건이 걸린 확장 (Conditional Extension)특정 타입일 때만 적용extension Collection where Element: Equatable

장점

  • 공통 코드를 한 번에 정의하여 코드 중복을 방지하고 일관성을 유지하게 한다.

기본 예시

protocol Describable {
    var name: String { get }
    func describe()
}

extension Describable {
    // 메서드
    func describe() {
        print("This is \(name)")
    }

    // 계산 프로퍼티
    var uppercasedName: String {
        name.uppercased()
    }

    // 중첩 타입
    enum Style {
        case short, detailed
    }
}

현실 예시

1. 공통 기능을 묶은 Ssg 프로토콜

protocol Ssg {
    func study()
}

2. Ssg 프로토콜을 확장해서 공통되는 동작은 기본 구현으로 제공

extension Ssg {
    func prepareForStudy() {
        print("주제를 정하고 이슈를 판다🔥")
    }
}

전체 코드 (실행 가능 🙆‍♀️)

import Foundation

// MARK: - Protocol 정의
protocol Ssg {
    func study()
}

// MARK: - Protocol Extension: 공통 기능 기본 구현 제공
extension Ssg {
    func prepareForStudy() {
        print("주제를 정하고 이슈를 판다🔥")
    }
}

// MARK: - 각 사람별 Struct 정의 및 채택
struct Jam: Ssg {
    func study() {
        print("브랜치 파자마자 성실하게 공부 시작🧐")
    }
}

struct Gus: Ssg {
    func study() {
        print("팀장에게 점수를 따기 위해 노력함🕺")
    }
}

// MARK: - 테스트
let jam = Jam()
jam.prepareForStudy() // "주제를 정하고 이슈를 판다🔥"
jam.study()           // "브랜치 파자마자 성실하게 공부 시작🧐"

let gus = Gus()
gus.prepareForStudy() // "주제를 정하고 이슈를 판다🔥"
gus.study()           // "팀장에게 점수를 따기 위해 노력함🕺"

+ Protocol Extension을 사용하지 않았더라면?

  • 아래와 같이 공통되는 코드를 반복해서 구현해야 했겠죠!
struct Jam: Ssg {
	func prepareForStudy() {
	        print("주제를 정하고 이슈를 판다🔥")
	    }
    func study() {
        print("브랜치 파자마자 성실하게 공부 시작🧐")
    }
}

struct Gus: Ssg {
	func prepareForStudy() {
	        print("주제를 정하고 이슈를 판다🔥")
	    }
    func study() {
        print("팀장에게 점수를 따기 위해 노력함🕺")
    }
}

조건부 확장

현실 세계 예시

1. 팀장만 채택할 프로토콜 생성

protocol TeamLeader {
    func giveScore(to member: Ssg)
}

2. TeamLeadergiveScore()를 쓸 수 있도록 조건부 제한걸기

extension Ssg where Self: TeamLeader {
    func giveScore() {
        print("\(self.name) 팀장이 \(member.name)에게 점수를 준다")
    }
}

전체 코드 (실행 가능 🙆‍♀️)

import Foundation

// MARK: - Protocol 정의
protocol Ssg {
    func study()
}

// MARK: - 팀장 전용 프로토콜 정의
protocol TeamLeader {
    func giveScore()
}

// MARK: - TeamLeader만 사용할 수 있는 기능 제공 (프로토콜 확장 + 제약조건)
extension Ssg where Self: TeamLeader {
    func giveScore() {
        print("팀원들에게 점수를 줌🎉")
    }
}

// MARK: - 각 사람별 Struct 정의 및 채택
struct Jam: Ssg {
    func study() {
        print("브랜치 파자마자 성실하게 공부 시작🧐")
    }
}

struct Gus: Ssg {
    func study() {
        print("팀장에게 점수를 따기 위해 노력함🕺")
    }
}

struct Jay: Ssg, TeamLeader {
	func study() {
        print("솔선수범하여 미리미리 공부함📑")
    }
}

// MARK: - 테스트
let jam = Jam()
jam.study()           // "브랜치 파자마자 성실하게 공부 시작🧐"

let gus = Gus()
gus.study()           // "팀장에게 점수를 따기 위해 노력함🕺"

let jay = Jay()
jay.study()           // "솔선수범하여 미리미리 공부함📑"
jay.giveScore() // "팀원들에게 점수를 줌🎉"

실제 예시

  • Collection 안의 요소가 Equatable일 때만 비교(==)가 가능
  • 따라서 Element: Equatable일 때만 allEqual() 메서드를 사용할 수 있게함
extension Collection where Element: Equatable {
    func allEqual() -> Bool {
        guard let first = self.first else { return true }
        return !self.contains { $0 != first }
    }
}
  • Equatable을 따르는 대표적인 타입
타입설명
Int, Double, Float숫자 비교 가능
String, Character문자열 비교 가능
Booltrue/false 비교 가능

References

0개의 댓글