소소한개발팁
article thumbnail
반응형

Methods 

- 특정 타입의 클래스, 구조체, 열거형과 관련된 함수를 메서드라 합니다.

- 특정 타입의 인스턴스에서 실행할 수 있는 메서드를 인스턴스 메서드, 특정 형과 관련된 메서드를 타입 메서드

- Swift에서는 클래스 타입뿐만 아니라 구조체, 열거형에서도 메서드를 선언해 사용할 수 있습니다.

 

 

Instance Methods 

- 인스턴스 메서드는 특정 클래스, 구조체, 열거형의 인스턴스에 속한 메서드입니다. 인스턴스 내의 값을 제어하거나 변경할 수 있습니다. 인스턴스 메서드는 이름 그대로 그 인스턴스가 속한 특정 타입의 인스턴스에서만 실행 가능합니다. 아래는 이에 대한 예시입니다.

 

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

 

- Counter클래스를 선언하고 인스턴스 메서드로 각각 increment(), increment(by amount: Int), reset()를 정의해 인스턴스 내의 count 변수를 변경하는 기능을 수행합니다.

 

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

 

 

The self Property 

- 모든 프로퍼티는 암시적으로 인스턴스 자체를 의미하는 self라는 프로퍼티를 갖습니다. 인스턴스 메서드 안에서 self 프로퍼티를 이용해 인스턴스 자체를 참조하는 데 사용할 수 있습니다.

 

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

 

- 앞의 예제에서 increment() 메서드에서는 count += 1이라 표현했지만 사실은 self.count += 1의 의미입니다.

 

- Swift에서 특정 메서드에서 해당 인스턴스에 등록된 메서드나 프로퍼티를 호출하면 현재 인스턴스의 메서드나 프로퍼티를 사용하는 것으로 자동으로 가정하기 때문입니다.

 

- 위 규칙이 적용되지 않는 예외적인 상황은 인자 이름이 프로퍼티 이름과 같은 경우입니다. 아래는 이 경우에 대한 예시입니다.

 

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"

 

- isToTheRightOf(x: Double) 메서드에서 self.x 를 사용해 프로퍼티 x와 인자 x 를 구분했습니다.

 

 

Modifying Value Types from Within Instance Methods 

- 구조체와 열거형은 값 타입입니다. 그래서 기본적으로 인스턴스 메서드 내에서 값 타입의 프로퍼티를 변경할 수 없습니다. 하지만 값 타입 형의 메서드에서 프로퍼티를 변경하고 싶을 때는 메서드에 mutating 붙여주면 가능합니다.

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는 구조체여서 메서드로 인스턴스의 값을 변경할 수 없지만 mutating func moveBy() 같이 메서드 앞에 mutating을 붙여서 값을 변경할 수 있습니다. 이때 point라는 구조체를 변수로 선언하여 변경할 수 있었지만 상수로 선언할 경우 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 프로퍼티를 이용해 정말 새로운 인스턴스를 생성할 수 있습니다. 위 메서드를 아래와 같이 작성할 수도 있습니다.

 

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)
    }
}

 

- 아래는 열거형일 때의 예시입니다.

 

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

 

 

Type Methods

- 인스턴스 메서드는 특정 타입의 인스턴스에서 호출되고, 타입 메서드는 특정 타입 자체에서 호출해 사용합니다.

 

- 타입 메서드의 선언은 메서드 키워드 func 앞에 static 혹은 class 키워드를 추가하면 됩니다.

 

- static 메서드와 class 메서드의 차이점은 static 메서드는 서브클래스에서 오버라이드 할 수 없는 타입 메서드이고,class 메서드는 서브클래스에서 오버라이드 할 수 있는 타입 메서드라는 것입니다.

 

- 아래는 타입 이름에서 메서드를 호출하는 예시입니다.

 

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
        }
    }
}

 

- 위 코드는 타입 메서드 3개와 mutating 메서드 1개를 선언해 현재 레벨과, 최고 레벨, 다음 레벨 열기, 다음 레벨로 넘어가기 기능을 구현했습니다.

 

- advance 메서드 앞에 붙은 @discardableResult 키워드는 리턴 값이 있는 메서드에서 리턴 값을 사용하지 않으면 컴파일러 경고가 발생하는데, 그 경고를 발생하지 않도록 해줍니다. 다시 말해 LevelTracker.advance라고 하면 이 메서드를 실행하고 나서Bool 값의 리턴 값을 어떤 변수에도 할당하지 않아 컴파일러 경고가 발생하지만 @discardableResult @discardableResult이라는 키워드를 붙이므로 이 결과 값은 버릴 수 있는 결과 값이라고 표시를 해서 경고가 발생하지 않도록 방지합니다.

위의 구조체를 이용하여 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
    }
}

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"

 

- player.tracker.complete 함수가 작동하지 않아서 "level 6 hasn't yet been unlocked"를 반환하는 것을 확인할 수 있습니다.

 

 

내용은 https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html를 보면서 작성하였고 원문으로 작성된 내용을 옮기다 보니 이상한 부분이 있을 수 있습니다. 자세한 내용은 위의 링크를 확인해주시기 바랍니다.

반응형
profile

소소한개발팁

@개발자 뱅

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!