메서드 (Methods) - 타입 메서드 (Type Methods)

00yhsp·2024년 5월 2일

위에 설명한 인스턴스 메서드는 특정 타입의 인스턴스에서 호출하는 메서드이다. 타입 자체에서 호출되는 메서드도 정의할 수 있다. 이런 종류의 메서드를 타입 메서드 (type methods) 라고 한다. 메서드의 func 키워드 전에 static 키워드를 작성하여 타입 메서드를 나타낸다. 클래스는 대신 class 키워드를 사용하여 하위 클래스가 해당 메서드의 상위 클래스 구현을 재정의할 수 있다.

Note
Objective-C에서는 Objective-C 클래스에 대해서만 타입 레벨 메서드 (type-level methods)를 정의할 수 있다. Swift에서는 모든 클래스, 구조체, 그리고 열거형에 대해서 타입 레벨 메서드를 정의할 수 있다. 각 타입 메서드는 지원하는 타입으로 명시적으로 범위가 지정된다.

타입 메서드는 인스턴스 메서드처럼 점 구문으로 호출된다. 그러나 해당 타입의 인스턴스가 아닌 타입으로 타입 메서드를 호출한다. SomeClass 라는 클래스에서 타입 메서드를 호출하는 방법은 다음과 같다:

class SomeClass {
    class func someTypeMethod() {
        // type method implementation goes here
    }
}
SomeClass.someTypeMethod()

타입 메서드의 본문 내에서 암시적 self 프로퍼티는 타입의 인스턴스가 아닌 타입 자체를 참조한다. 인스턴스 프로퍼티와 인스턴스 메서드 파라미터에서와 같이 self 를 타입 프로퍼티와 타입 메서드 파라미터를 명확하게 하기위해 사용할 수 있다는 의미이다.

일반적으로 타입 메서드의 본문 내에서 사용하는 정규화되지 않은 메서드와 프로퍼티 이름은 다른 타입 레벨 메서드와 프로퍼티를 참조한다. 타입 메서드는 타입 이름을 접두어로 필요치 않고 다른 메서드의 이름으로 다른 타입 메서드를 호출할 수 있습니다. 유사하게 구조체와 열거형에서 타입 메서드는 타입 이름 접두어 없이 타입 프로퍼티의 이름을 사용하여 타입 프로퍼티에 접근할 수 있다.

아래 예제는 게임의 다른 레벨 또는 스테이지를 통해 사용자의 진행상황을 추적하는 LevelTracker 라는 구조체를 정의한다. 이것은 1인용 게임이지만 단일 디바이스에서 여러명의 플레이어를 위한 정보를 저장할 수 있다.

첫번째 레벨을 제외한 게임의 모든 레벨은 게임을 처음 플레이할 때 잠겨 있다. 플레이어가 레벨을 끝낼 때마다 디바이스에 모든 플레이어가 플레이 할 수 있도록 레벨이 풀린다. LevelTracker 구조체는 게임의 레벨이 풀리는 것을 추적하기 위해 타입 프로퍼티와 메서드를 사용한다. 각 플레이어의 현재 레벨도 추적한다.

struct LevelTracker {
    static var highestUnlockedLevel = 1
    var currentLevel = 1

    static func unlock(_ level: Int) {
        if level > highestUnlockedLevel { highestUnlockedLevel = level }
    }

    static func isUnlocked(_ level: Int) -> Bool {
        return level <= highestUnlockedLevel
    }

    @discardableResult
    mutating func advance(to level: Int) -> Bool {
        if LevelTracker.isUnlocked(level) {
            currentLevel = level
            return true
        } else {
            return false
        }
    }
}

LevelTracker 구조체는 모든 플레이어가 푼 가장 높은 레벨을 추적합니다. 이 값은 highestUnlockedLevel 이라는 타입 프로퍼티에 저장된다.

LevelTracker 는 highestUnlockedLevel 프로퍼티와 함께 동작하는 2개의 타입 함수도 정의한다. 첫번째 타입 함수는 unlock(:)이라 하며 새로운 레벨이 풀릴 때마다 highestUnlockedLevel 의 값을 업데이트한다. 두번째 타입 함수는 isUnlocked(:) 이라 하며 편의 타입 함수이며 특정 레벨이 이미 풀려있다면 true 를 반환한다 (이 타입 메서드는 LevelTracker.highestUnlockedLevel 로 작성할 필요 없이 highestUnlockedLevel 타입 프로퍼티를 접근할 수 있다).

타입 프로퍼티와 타입 메서드 외에도 LevelTracker는 게임을 통해 각 플레이어의 진행사항을 추적한다. 플레이어가 현재 플레이 중인 레벨을 추적하는 currentLevel 이라는 인스턴스 프로퍼티를 사용합니다.

currentLevel 프로퍼티 관리를 돕기위해 LevelTracker 는 advance(to:) 라는 인스턴스 메서드를 정의한다. currentLevel 업데이트 전에 이 메서드는 요청된 새 레벨이 이미 풀렸는지 판단한다. advance(to:) 메서드는 currentLevel 을 설정가능한지 아닌지를 나타내기 위해 부울값으로 반환한다. advance(to:) 메서드를 호출하여 반환값을 무시하는 코드가 실수가 아니기 때문에 이 함수는 @discardableResult 속성으로 표시된다.

LevelTracker 구조체는 아래에서 봤듯이 각 플레이어의 진행상태를 추적하고 업데이트 하기 위해 Player 클래스와 함께 사용된다:

class Player {
    var tracker = LevelTracker()
    let playerName: String
    func complete(level: Int) {
        LevelTracker.unlock(level + 1)
        tracker.advance(to: level + 1)
    }
    init(name: String) {
        playerName = name
    }
}

Player 클래스는 플레이어의 진행상태를 추적하기 위해 새로운 LevelTracker 의 인스턴스를 생성한다. 플레이어가 특정 레벨을 완료했는지 판단하는 complete(level:) 이라는 메서드도 제공한다. 이 메서드는 모든 플레이어에게 다음 레벨을 풀고 다음 레벨로 이동하기 위해 플레이어의 진행상태를 업데이트 한다 (이전 라인에서 LevelTracker.unlock(_:) 을 호출하여 해당 레벨을 풀기 때문에 advance(to:) 의 부울 반환 값은 무시된다).

새로운 플레이어를 위한 Player 클래스의 인스턴스를 생성할 수 있고 플레이어가 레벨1을 완료하면 어떤 일이 생기는지 알 수 있다:

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

게임에서 아직 풀리지 않은 레벨로 이동을 하려는 2번째 플레이어를 생성하면 플레이어의 현재 레벨을 실패로 설정합니다:

player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
    print("player is now on level 6")
} else {
    print("level 6 has not yet been unlocked")
}
// Prints "level 6 has not yet been unlocked"
profile
iOS Dev

0개의 댓글