🔥 타입 메서드

773자
10분

저번에는 인스턴스 메서드에 대해 알아봤습니다. 인스턴스 메서드는 특정 타입의 인스턴스에서 호출되는 메서드였죠. 이번에는 타입 자체에서 호출되는 메서드인 type methods에 대해 알아보겠습니다. 타입 메서드는 메서드의 func 키워드 앞에 static 키워드를 작성하여 표시합니다. 클래스의 경우 서브클래스가 슈퍼클래스의 메서드 구현을 override 할 수 있도록 class 키워드를 사용할 수도 있어요.

타입 메서드는 인스턴스 메서드처럼 dot syntax를 사용하여 호출됩니다. 하지만 타입 메서드는 해당 타입의 인스턴스가 아닌 타입 자체에서 호출되는 것이 차이점이에요. 다음은 SomeClass라는 클래스에서 타입 메서드를 호출하는 방법입니다:

class SomeClass {
    class func someTypeMethod() {
        // 타입 메서드 구현 내용
    }
}
SomeClass.someTypeMethod()
swift

타입 메서드의 내부에서 암시적 self 속성은 해당 타입의 인스턴스가 아닌 타입 자체를 참조합니다. 이는 인스턴스 속성과 인스턴스 메서드 매개변수에서 self를 사용하여 구분하는 것처럼, 타입 속성과 타입 메서드 매개변수를 구분하기 위해 self를 사용할 수 있다는 의미예요.

더 일반적으로, 타입 메서드 내부에서 사용하는 모든 메서드와 속성 이름은 다른 타입 레벨의 메서드와 속성을 참조합니다. 타입 메서드에서는 타입 이름을 접두사로 사용하지 않고도 다른 타입 메서드의 이름만으로 호출할 수 있어요. 비슷하게, 구조체와 열거형의 타입 메서드에서는 타입 이름 접두사 없이 타입 속성의 이름만으로 접근할 수 있습니다.

아래의 예제는 LevelTracker라는 구조체를 정의하고 있어요. 이 구조체는 게임의 다양한 레벨이나 스테이지를 통해 플레이어의 진행 상황을 추적합니다. 싱글 플레이어 게임이지만, 하나의 디바이스에서 여러 플레이어의 정보를 저장할 수 있죠.

게임의 모든 레벨(레벨 1 제외)은 처음 플레이할 때 잠겨 있습니다. 플레이어가 레벨을 완료할 때마다, 해당 레벨은 디바이스의 모든 플레이어에 대해 잠금 해제됩니다. LevelTracker 구조체는 타입 속성과 메서드를 사용하여 게임의 어떤 레벨이 잠금 해제되었는지 추적해요. 또한 개별 플레이어의 현재 레벨도 추적합니다.

struct LevelTracker {
    static var highestUnlockedLevel = 1  // 잠금 해제된 가장 높은 레벨을 저장하는 타입 속성
    var currentLevel = 1                // 현재 플레이어의 레벨을 저장하는 인스턴스 속성
 
    static func unlock(_ level: Int) {
        // 새로운 레벨이 잠금 해제되면 highestUnlockedLevel 값을 업데이트하는 타입 메서드
        if level > highestUnlockedLevel { highestUnlockedLevel = level }
    }
 
    static func isUnlocked(_ level: Int) -> Bool {
        // 특정 레벨이 이미 잠금 해제되었는지 확인하는 편의 타입 메서드
        return level <= highestUnlockedLevel
    }
 
    @discardableResult
    mutating func advance(to level: Int) -> Bool {
        // 요청된 새 레벨이 이미 잠금 해제되었는지 확인한 후 currentLevel을 업데이트하는 인스턴스 메서드
        if LevelTracker.isUnlocked(level) {
            currentLevel = level
            return true
        } else {
            return false
        }
    }
}
swift

LevelTracker 구조체는 모든 플레이어가 잠금 해제한 가장 높은 레벨을 추적합니다. 이 값은 highestUnlockedLevel이라는 타입 속성에 저장됩니다.

LevelTracker는 또한 highestUnlockedLevel 속성과 함께 작동하는 두 개의 타입 함수를 정의하고 있어요:

  • unlock(_:): 새로운 레벨이 잠금 해제될 때마다 highestUnlockedLevel의 값을 업데이트하는 타입 함수
  • isUnlocked(_:): 특정 레벨 번호가 이미 잠금 해제되었는지 여부를 반환하는 편의 타입 함수

(이 타입 메서드에서는 highestUnlockedLevel 타입 속성에 LevelTracker.highestUnlockedLevel처럼 작성할 필요 없이 접근할 수 있습니다.)

타입 속성과 타입 메서드 외에도 LevelTracker는 개별 플레이어의 게임 진행 상황을 추적합니다. currentLevel이라는 인스턴스 속성을 사용하여 플레이어가 현재 플레이 중인 레벨을 추적하죠.

currentLevel 속성을 관리하기 위해 LevelTrackeradvance(to:)라는 인스턴스 메서드를 정의합니다. currentLevel을 업데이트하기 전에 이 메서드는 요청된 새 레벨이 이미 잠금 해제되었는지 확인해요. advance(to:) 메서드는 실제로 currentLevel을 설정할 수 있었는지 여부를 나타내기 위해 Boolean 값을 반환합니다. advance(to:) 메서드를 호출하는 코드에서 반환 값을 무시하는 것이 반드시 실수는 아니므로, 이 함수에는 @discardableResult 속성이 표시되어 있어요. 이 속성에 대한 자세한 내용은 Attributes를 참조하세요.

LevelTracker 구조체는 아래와 같은 Player 클래스와 함께 사용되어 개별 플레이어의 진행 상황을 추적하고 업데이트합니다:

class Player {
    var tracker = LevelTracker()  // 플레이어의 진행 상황을 추적하기 위해 LevelTracker의 새 인스턴스 생성
    let playerName: String
 
    func complete(level: Int) {
        // 플레이어가 특정 레벨을 완료할 때마다 호출되는 메서드
        LevelTracker.unlock(level + 1)  // 모든 플레이어에 대해 다음 레벨 잠금 해제
        tracker.advance(to: level + 1)  // 플레이어를 다음 레벨로 이동
    }
 
    init(name: String) {
        playerName = name
    }
}
swift

Player 클래스는 해당 플레이어의 진행 상황을 추적하기 위해 LevelTracker의 새 인스턴스를 생성합니다. 또한 플레이어가 특정 레벨을 완료할 때마다 호출되는 complete(level:) 메서드를 제공하죠. 이 메서드는 모든 플레이어에 대해 다음 레벨을 잠금 해제하고 플레이어의 진행 상황을 업데이트하여 다음 레벨로 이동시킵니다. (advance(to:)의 Boolean 반환 값은 이전 줄에서 LevelTracker.unlock(_:) 호출에 의해 레벨이 잠금 해제된 것으로 알려져 있기 때문에 무시됩니다.)

새로운 플레이어를 위해 Player 클래스의 인스턴스를 생성하고 플레이어가 레벨 1을 완료할 때 어떤 일이 발생하는지 확인할 수 있어요:

var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// "highest unlocked level is now 2" 출력
swift

두 번째 플레이어를 생성하고 게임에서 아직 어떤 플레이어도 잠금 해제하지 않은 레벨로 이동하려고 하면, 플레이어의 현재 레벨을 설정하려는 시도는 실패합니다:

player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
    print("player is now on level 6")
} else {
    print("level 6 hasn't yet been unlocked")
}
// "level 6 hasn't yet been unlocked" 출력
swift

이렇게 타입 메서드를 활용하면 타입 자체에서 호출되는 메서드를 정의할 수 있습니다. 타입 메서드는 타입 속성과 함께 사용되어 해당 타입과 관련된 값이나 기능을 관리하는 데 유용하게 사용될 수 있어요. 위의 예제처럼 게임의 전체적인 상태를 관리하면서 개별 플레이어의 진행 상황을 추적하는 것과 같은 시나리오에 적합하죠.