GGURUPiOS

Swift 공식 문서 정리 - (11) Methods 본문

Swift/공식문서 정리 ( 문법 )

Swift 공식 문서 정리 - (11) Methods

꾸럽 2023. 4. 27. 20:33

메소드 (Methods)

메소드는 특정 유형과 연관된 함수임

클래스, 구조 및 열거형은 모두 지정된 유형의 인스턴스로 작업하기 위한

특정 작업 및 기능을 캡슐화하는 인스턴스 메서드를 정의 가능.

인스턴스 메소드

특정 클래스, 구조체, 열거형의 인스턴스에 속한 메소드임.

인스턴스 내의 값을 제어하거나 변경 가능.

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

let counter = Counter()
// 초기 count 값은 0입니다.
counter.increment()
// count 값이 1로 변경 됐습니다.
counter.increment(by: 5)
// count 값은 현재 6입니다.
counter.reset()
// count 값은 0이 됩니다.

// 함수를 한번이라도 짜 봤다면 어려운건 없어보인다.

self 프로퍼티

모든 프로퍼티는 암시적으로 인스턴스 자체를 의미하는 self 프로퍼티를 갖는다

인스턴스 메소드 안에서 self 프로퍼티를 이용해 인스턴스 자체를 참조하는데 사용 가능 함

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

특정 메소드에서 해당 인스턴스에 등록된 메소드나 프로퍼티를 호출하면 현재 인스턴스의

메소드나 프로퍼티를 사용하는 것으로 자동으로 가정함

그러나 위 규칙이 적용 안되는 예외적인 상황이 있음

인자 이름이 프로퍼티 이름과 같은 경우임.

이럴때는 명시적으로 self 키워드를 사용해야 함 ( 모호함을 피함 )

struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
        return self.x > x  // self.x를 이용해 프로퍼티 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")
}
// "This point is to the right of the line where x == 1.0" 출력

만약 프로퍼티와 인자 이름이 같을 때 self 키워드를 사용하지 않으면 스위프트는 자동으로 인자 이름으로 가정 함

인스턴스 메소드 내에서 값 타입 변경

구조체와 열거형은 값 타입임 → 메소드 내에서 값 타입의 프로퍼티를 변경할 수 없음

하지만 값 타입 형의 메소드에서 프로퍼티를 변경하고 싶을 때는 ?

→ 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))")
// "The point is now at (3.0, 4.0)" 출력

하지만 var somePoint 를 let 으로 선언하면 구조체 단에서 변경이 불가능 하다는 선언이기 때문에

mutating선언과 상관없이 메소드로 값을 변경할 수 없음

Mutating 메소드 내에서 self 할당

Mutating 메소드에서 self 프로퍼티를 이용해 완전 새로운 인스턴스를 생성할 수 있음

아래 예제의 동작은 위의 예제의 동작과 일치 함

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 메소드를 새용해 다른 상태로 표현도 가능 하다.

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 값은 .high
ovenLight.next()
// ovenLight 값은 .off

타입 메소드

타입 메소드는 특정 타입 자체에서 호출해 사용한다.

선언은 func 앞에 static 혹은 class 키워드를 추가하면 된다.

타입 프로퍼티와 마찬가지로 static과 class의 차이는 오버라이드 여부 임 ( X / O )

호출은 점 문법으로 가능하며 인스턴스에서 호출하는 것이 아닌 타입 이름에서 호출 함

class SomeClass {
    class func someTypeMethod() {
        // 타입 메소드 구현
    }
}
SomeClass.someTypeMethod()    // 타입 메소드 호출!

~~SomeClass().someTypeMethod() // 인스턴스를 생성해서 호출 X~~ 

타입 메소드 안에서도 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
        }
    }
}

// @discardableResult -> 반환 값이 있지만, 그 값을 버릴 수 있다는 키워드

위 코드는 타입 메소드 2개, mutating 메소드 1개로

현재 레벨, 최고 레벨, 다음 레벨열기, 다음 레벨 넘어가기 기능이 구현되어있음

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의 클래스의 complete 메소드에서 LevelTracker 인스턴스 tracker 와

타입메소드 LevelTracker.unlock을 사용해 특정 사용자의 현재 레벨을 추적하도록 구현됨

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

레벨 1을 완료한 모습 → 레벨 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")
}
// "level 6 has not yet been unlocked" 출력

잠금을 해제하지 않은 레벨로 이동하려는 경우