티스토리 뷰

 

 

Methods — The Swift Programming Language (Swift 5.5)

Methods Methods are functions that are associated with a particular type. Classes, structures, and enumerations can all define instance methods, which encapsulate specific tasks and functionality for working with an instance of a given type. Classes, struc

docs.swift.org

1차 수정 (2022 / 02 / 27) : 의역, 오타 및 스타일 수정

 

 

 

Methods

메소드는 특정 타입과 연관이 있는 함수입니다. 클래스, 구조체, 열거형은 모두 인스턴스 메소드를 정의할 수 있습니다. 인스턴스 메소드는 주어딘 타입의 인스턴스로 작업하기 위한 특정 작업과 기능을 캡슐화합니다. 클래스, 구조체, 열거형은 타입 자체와 연관된 타입 메소드도 정의할 수 있습니다. 타입메소드는 Objective-C의 클래스 메소드와 유사합니다.

 

Swift에서 구조체와 열거형에 메소드를 정의한다는 사실은 C, Objective-C와는 큰 차이점입니다. Objective-C 에서 클래스가 메소드를 정의할 수 있는 유일한 타입입니다. Swift에서는 클래스, 구조체, 열거형 중에서 선택할 수 있고, 사용자가 만든 타입에 대해서도 메서드를 정의할 수 있습니다.

 

 

 

 

Instance Methods(인스턴스 메소드)

인스턴스 메소드는 특정 클래스, 구조체, 열거형의 인스턴스에 속하는 함수입니다. 인스턴스에 기능을 지원합니다. 인스턴스 프로퍼티에 접근하고 수정할 수 있는 방법을 제공하고, 인스턴스의 목적에 맞는 기능을 제공합니다. 인스턴스 메소드는 함수와 동일한 구문을 가집니다.

 

인스턴스 메소드는 메소드가 속한 타입의 중괄호 { } 안에 작성합니다. 인스턴스 메소드는 해당 타입의 다른 모든 인스턴스 메소드 및 프로퍼티에 암시적(implict)으로 접근할 수 있습니다. 인스턴스 메소드는 해당 메서드가 속한 타입의 특정 인스턴스에 대해서만 호출할 수 있습니다. 기존의 인스턴스 없이는 혼자 호출될 수 없습니다.

 

class Counter {
    var count = 0
    func increment() {
        count += 1
    }
    func increment(by amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}

Counter 클래스는 count라는 프로퍼티와 세가지 인스턴스 메소드를 정의합니다.

  • increment() : count를 1 증가시킴
  • increment(by: Int) : count를 특정 int 수 만큼 증가시킴
  • reset() : count를 0으로 재설정함

.구문을 사용해 인스턴스 메소드를 호출합니다.

let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1
counter.increment(by: 5)
// the counter's value is now 6
counter.reset()
// the counter's value is now 0

함수 파라미터(매개변수)에는 이름와 인수 레이블(argument label)이 모두 있을 수 있습니다. 메소드는 타입과 관련된 함수이기 때문에 메소드의 파라미터에도 마찬가지입니다. (by만 사용해도 되고 by와 amount를 같이 사용해도 된다)

 

 

 

The self Property(셀프 프로퍼티)

모든 인스턴스 타입은 암시적으로 self라 불리는 property를 가집니다. self는 인스턴스 그 자체와 동일합니다. self 프로퍼티를 사용하여 자체 인스턴스(instance) 메소드 내의 현재 인스턴스를 참조할 수 있습니다.

 

func increment() {
        count += 1
}
///
func increment() {
    self.count += 1
}

위 예제의 increment() 함수에 self를 추가해서 작성할 수 있습니다. 실제로 코드에 self를 자주 쓸 필요는 없습니다.  명시적으로 self를 작성하지 않으면, Swift는 메소드에서 알려진 타입 또는 메소드 이름을 사용할 때마다, 현재 인스턴의 프로퍼티 또는 메소드를 참조하는 것으로 가정합니다.

 

이 규칙의 주 예외는 인스턴스 메소드의 파라미터 이름이 해당 인스턴스의 프로퍼티와 이름이 같을 때 일어납니다. 이 경우, 파라미터 이름이 우선시 되므로 더 정규화된 방식으로 프로퍼티를 참조할 필요가 있습니다. 파라미터 이름과 프로퍼티 이름을 구별하기 위해 self 프로퍼티를 사용합니다.

(즉 인수와 안에 선언한 변수의 이름이 같을 때, 안에 있는 변수에 접근하기 위해 self를 쓴다)

 

struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
        return self.x > x
    }
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
    print("This point is to the right of the line where x == 1.0")
}
// Prints "This point is to the right of the line where x == 1.0"

self 키워드가 없으면, Swift는 두 개의 x 모두 파라미터의 x 로 가정합니다. 

(self.x는 var에 선언된 x, 오른쪽 x는 isToTheRightof메소드의 파라미터 x)

 

 

 

 

Modifying Value Types from Within Instance Methods(인스턴스 메소드에서 값타입 수정)

구조체와 열거형은 값타입(value types)입니다. 기본적으로 값타입의 프로퍼티는 인스턴스 메소드로 수정될 수 없습니다.

 

하지만, 특정 메소드를 통해 구조체와 열거형의 프로퍼티를 수정할 필요가 있다면, 해당 메소드에 대한 동작을 변경(mutating) 하도록 선택할 수 있습니다. 메소드는, 메소드 내에서 프로퍼티를 변경할 수 있으며 메소드가 종료될 때 모든 변경사항이 기존 구조체에 다시 기록됩니다. 메소드는 암시적 self 프로퍼티에 완전히 새로운 인스턴스를 할당할 수도 있으며, 메소드가 끝날 때 이 새로운 인스턴스는 기존 인스턴스를 대체합니다.

 

메소드의 func 키워드 앞에 mutating 키워드를 작성함으로써 이 동작을 선택할 수 있습니다.

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Prints "The point is now at (3.0, 4.0)"

예제의 Point 구조체는 point를 특정 거리만큼 이동시키는 mutating mobeBy 메소드를 정의합니다. 새로운 값을 리턴하는 대신에, 이 메소드는 호출한 point를 수정합니다. 프로퍼티를 수정할 수 있도록 mutating 키워드가 정의에 추가됩니다.

 

구조체 타입의 상수에 대해서는 mutating 메소드를 호출할 수 없습니다. 변수 프로퍼티일지라도 해당 프로퍼티는 수정할 수 없기 때문입니다.

let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// this will report an error

 

 

 

 

 

Assigning to self Within a Mutating Method(Mutating 메소드로 self에게 할당)

Mutating 메소드는 암시적 self 프로퍼티에 완전히 새로운 인스턴스를 할당할 수 있습니다. 위의 Point 예제는 아래와 같이 작성될 수 있습니다.

 

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}

위 예제의 mutating moveBy 메소드는 x와 y 값이 대상 위치로 설정된 새로운 구조체를 생성합니다. 이 메소드를 호출한 최종결과는 기존의 예제와 완전히 같을 것 입니다.

 

열거형의 mutating 메소드는 암시적 self 파리머터를 열거형 내의 다른 케이스로 설정할 수 있습니다.

enum TriStateSwitch {
    case off, low, high
    mutating func next() {
        switch self {
        case .off:
            self = .low
        case .low:
            self = .high
        case .high:
            self = .off
        }
    }
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
// ovenLight is now equal to .high
ovenLight.next()
// ovenLight is now equal to .off

위 예제는 열거형을 3가지 상태로 정의합니다. next 메소드가 호출될 때마다 3가지 다른 상태를 순환합니다.

 

 

 

 

 

 

Type Methods (타입 메소드)

인스턴스 메소드는 `특정 타입의 인스턴스에 대해 호출할 수 있는 메소드`입니다. 타입 자신을 호출하는 메소드도 정의할 수 있습니다. 이런 종류의 메소드를 타입 메소드라고 부릅니다. func 키워드 앞에 static 키워드를 사용해 이 타입 메소드를 지칭합니다. 클래스는 class 키워드를 대신 사용해, 하위 클래스가 해당 메소드의 슈퍼클래스 실형을 재정의할 수 있습니다.

 

Objective-C 에서 Objective-C 클래스만을 위해 타입 레벨의 메소드를 정의할 수 있었습니다. Swift에서는 모든 클래스, 구조체, 열거형에 대해 타입 레벨의 메소드를 정의할 수 있습니다. 각각의 타입 메소드는 명시적으로 지원하는 타입으로 범위가 지정됩니다.

 

타입 메소드는 . 을 사용해 호출합니다. 인스턴스 메소드가 아닌 타입(클래스, 구조체, 열거형) 에 대해 . 을 사용해야합니다.

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

타입 메소드의 실행문 안에 암시적 self 프로퍼티가 타입의 인스턴스 대신에, 타입 자신을 참조합니다. 즉, self를 사용하여 타입 프로퍼티와 타입 메소드 파라미터를 명확히 구별할 수 있습니다. (인스턴스 프로퍼티와 인스턴스 메소드 파라미터 구별 방식과 동일하다)

 

더 일반적으로, `타입 메소드 실행문 안에서 사용되는 모든 부적절한 메소드와 프로퍼티의 이름`은 다른 타입 레벨 메소드와 프로퍼티를 참조합니다. 타입 메소드는 . 앞에 타입의 이름을 붙이지 않고도, 다른 메소드 이름을 통해 다른 타입의 메소드를 호출할 수 있습니다. 비슷하게 구조체와 열거형의 타입 메소드도 . 앞에 타입 이름을 사용할 필요없이 타입 프로퍼티 이름만을 사용해 타입 프로퍼티에 접근할 수 있습니다.

 

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 프로퍼티를 사용할 두가지 타입의 함수도 정의합니다. unlock(_:) 함수는 새로운 레벨이 해제되면 highestUnlockedLevel 값을 업데이트합니다. isUnlocked(_:) 함수는 특정 레벨이 이미 해제되어 있으면 ture를 리턴합니다. (highestUnlockedLevel 에 접근할 때 LevelTracker.highestUnlockedLevel 로 접근하지 않아도 됩니다)

 

타입 프로퍼티와 타입 메소드 외에도, LevelTracker 는 개별 플레이어를 추적합니다. currentLevel 라는 인스턴스 프로퍼티를 사용하여 플레이어가 현재 재생 중인 레벨을 추적합니다.

 

currentLevel 프로퍼티 관리를 돕기위해, LevelTracker 는 advance(to:) 라는 인스턴스 메소드를 정의합니다. currentLevel 을 업데이트 하기전에, 이 메소드는 요청된 새로운 레벨이 이미 해제되었는지 확인합니다. advance(to:) 메소드는 실제로 currentLevel 을 설정할 수 있는지, Boolean 값을 리턴합니다. 코드를 위해 `리턴 값을 무시하기 위해서 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:)라는 메소드도 제공합니다. 이 메소드는 모든 유저를 위해 새로운 레벨을 해제하고 플레이어의 진행을 업데이트하여 다음 단계로 이동시킵니다. ( advance(to:) 의 Boolean 리턴 값은 무시됩니다. advance(to:) 윗 줄의 LevelTracker.unlock(_:) 호출에 의해 레벨이 잠금해제 되었기 때문입니다.)

 

새로운 플레이어를 위해 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"

 

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

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")
}
// Prints "level 6 hasn't yet been unlocked"

현재 레벨 1이 최고 레벨인데, 아직 잠금 해제되지 않은 레벨 6으로 플레이어를 만들면 레벨 설정이 실패합니다.

 

 

 

 

 

 

 

메소드 끝😁

 

 

 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함