카테고리 없음

[SWIFT] 메서드( 특정 타입에 관련된 함수 - 인스턴스메서드, 타입메서드)

알로하리미 2021. 3. 12. 13:45
728x90

1. 개요

스위프트에서 매세드는 특정 타입에 관련된 함수를 뜻함.

클래스, 구조체, 열거형에서 관련된 기능을 제공 하는 "인스턴스 메서드" 정의 가능

타입만으로 접근 가능한 "타입 메서드" 정의 가능

구조체와 열거형이 메서드를 가질 수 있다는 것은 기존 언어와의 다른점

 

 

2. 인스턴스 메서드(Instance Methods)

특정 타입의 인스턴스에 속한 함수( 타입(클래스,구조체,열거형) 내부에 구현 )

인스턴스 내부의 프로퍼티 값을 변경하거나 특정 연산 결과를 반환하는 등

인스턴스와 관련된 기능을 실행( 즉, 인스턴스가 존재할때만 수행 가능 )
class Counter {

    var count = 0
    
    func increment() {
        count += 1 //self.count += 1 이라는 표현과 같음.
        // 이것이 가능한 이유는 Swift에서 특정 메소드에서 
        // 해당 인스턴스에 등록된 메소드나 프로퍼티를 호출하면 
        // 현재 인스턴스의 메소드나 프로퍼티를 사용하는 것으로 
        // 자동으로 가정하기 때문입니다
        
        // 만약 매개변수가 있고 그 매개변수 이름이
        // 프로퍼티 이름과 같은 경우에는 
        // self로 프로퍼티랑 매개변수랑 구분을 확실히 해줘야한다.
    }
    
    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프로퍼티를 이용해 인스턴스 자체를 참조하는데 사용할 수 있습니다.

//위의 Counter클래스의 인스턴스 매서드 increment를 아래처럼 표현 가능
func increment() {
    self.count += 1
}
struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
        return self.x > x  
        // 매개변수 이름과 프로퍼티의 이름이 동일할시 self로 구분
        // 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" 출력

 

 

구조체와 열거형(값 타입)의 "인스턴스 메서드"에서 프로퍼티 변경

키워드 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)" 출력



let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// 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

 

 

 

 

3. 타입 메서드(Type Methods)

특정 타입 자체에서 호출해 사용합니다.

func앞에 static혹은 class키워드를 추가

타입 변수와 마찬가지로 static메소드와 class메소드의 차이점은

static메소드는 서브클래스에서 오버라이드 할 수 없는 타입 메소드 이고,

class메소드는 서브클래스에서 오버라이드 할 수 있는 타임 메소드 라는 것.

Swift에서는 클래스, 구조체, 열거형에서 모두 타입 메소드를 사용할 수 있습니다

 

 

타입 메소드도 인스턴스 메소드와 같이 점(.) 문법으로 호출할 수 있습니다.
하지만 인스턴스에서 호출하는 것이 아니라 타입 이름에서 메소드를 호출

class SomeClass {
    class func someTypeMethod() {
        // 타입 메소드 구현
    }
}
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 { 
        //레벨이 지금까지의 최고레벨 이하이면 true
        //즉, 이 레벨은 지금 unlock된 최고 레벨 이하이니 이 레벨은 해제되어있다.
        return level <= highestUnlockedLevel
    }

    @discardableResult // 반환값 사용 안해도 되니 경고 표시 하지말아요~    
    mutating func advance(to level: Int) -> Bool { // 다음 레벨로 넘어가기 인스터스메서드
        if LevelTracker.isUnlocked(level) { 
            // 그 다음레벨이 해제 되어있냐?
            //해제 되었으면 그 레벨이 현재 레벨로 지정.
            currentLevel = level  
            return true
        } else {
            // 해제 안되있으면 false 이 레벨은 해제가 안되어있으니 못들어간다.
            return false 
        }
    }
}

 

Player클래스의 complete메소드에서 LevelTracker 인스턴스 tracker와 타입메소드 LevelTracker.unlock를 사용해 특정 사용자의 현재 레벨을 추적하도록 구현

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



// 레벨 1을 완료해서 레벨 2가 열렸습니다.
var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// "highest unlocked level is now 2" 출력


// 다른 플레이어가 레벨 6에 접근 -> 아직 열리지 않음. 
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" 출력