Swift 프로토콜의 활용: 클래스, 구조체, 열거형에서의 구현 방법

Swift에서 프로토콜은 특정 기능에 필요한 메서드, 프로퍼티 및 기타 요구사항의 청사진을 정의합니다. 프로토콜을 실제 타입에서 채택하고 구현할 때는 타입의 특성(참조 타입 또는 값 타입)에 따라 get, set 요구사항과 mutating 키워드의 사용법을 정확히 이해해야 합니다.

1. 프로퍼티 요구사항: get과 set

프로토콜에서 프로퍼티를 정의할 때는 해당 프로퍼티가 읽기 전용인지, 혹은 읽기와 쓰기가 모두 가능한지를 명시해야 합니다.

var identifier: String { get }

위와 같이 선언된 프로퍼티는 구현체에서 최소한 읽기 기능(get)을 제공해야 함을 의미합니다.

var identifier: String { get set }

반면, get set이 모두 명시된 경우 구현체는 반드시 읽기와 쓰기가 모두 가능한 변수 프로퍼티로 이를 구현해야 합니다.

2. 값 타입을 위한 mutating 키워드

클래스와 달리 구조체(Struct)나 열거형(Enum)은 값 타입(Value Type)입니다. 프로토콜의 메서드가 인스턴스 내부의 상태를 변경해야 한다면, 프로토콜 정의 시 메서드 앞에 mutating 키워드를 추가해야 합니다. 클래스에서 이를 구현할 때는 mutating을 생략할 수 있지만, 구조체나 열거형에서는 필수적으로 명시해야 합니다.

3. 프로토콜 정의 예시

상태를 나타내는 프로퍼티와 상태를 변경하는 메서드를 포함하는 프로토콜을 다음과 같이 정의할 수 있습니다.

protocol Toggleable {
    var currentState: String { get }
    mutating func toggle()
}

4. 클래스(Class)에서의 구현

클래스는 참조 타입이므로 메서드 내에서 프로퍼티를 수정할 때 별도의 키워드가 필요하지 않습니다.

class DeviceManager: Toggleable {
    var currentState: String = "Off"
    
    func toggle() {
        if currentState == "Off" {
            currentState = "On"
        } else {
            currentState = "Off"
        }
    }
}

let manager = DeviceManager()
manager.toggle()
print(manager.currentState) // "On" 출력

클래스 인스턴스를 let으로 선언하더라도 클래스 내부의 가변 프로퍼티는 수정이 가능합니다.

5. 구조체(Struct)에서의 구현

구조체에서 프로토콜의 수정 메서드를 구현할 때는 반드시 mutating을 붙여야 합니다.

struct LightSwitch: Toggleable {
    var currentState: String = "Internal Off"
    
    mutating func toggle() {
        currentState = (currentState == "Internal Off") ? "Internal On" : "Internal Off"
    }
}

var mySwitch = LightSwitch()
mySwitch.toggle()
print(mySwitch.currentState)

구조체는 값 타입이므로 인스턴스 상태를 변경하려면 해당 인스턴스가 var로 선언되어야 합니다. let으로 선언된 구조체 인스턴스에서는 toggle() 메서드를 호출할 수 없습니다.

6. 열거형(Enum)에서의 구현

Swift의 열거형은 연관값(Associated Values)을 가질 수 있으며, 프로토콜 요구사항을 충족하기 위해 계산된 프로퍼티와 mutating 메서드를 사용할 수 있습니다.

enum OperationState: Toggleable {
    case active(String), inactive(String)
    
    var currentState: String {
        switch self {
        case .active(let message):
            return "Active: \(message)"
        case .inactive(let message):
            return "Inactive: \(message)"
        }
    }
    
    mutating func toggle() {
        switch self {
        case .active(let msg):
            self = .inactive(msg)
        case .inactive(let msg):
            self = .active(msg)
        }
    }
}

var state = OperationState.inactive("System standby")
print(state.currentState)
state.toggle()
print(state.currentState)

열거형에서의 mutating 메서드는 self 자체를 새로운 케이스로 교체하는 방식으로 상태 변경을 수행합니다. 프로토콜에서 정의된 get 요구사항은 열거형의 연관값을 활용한 계산된 프로퍼티로 깔끔하게 구현할 수 있습니다.

태그: Swift iOS Protocol struct Enum

8월 5일 06:06에 게시됨