Swift

Swift: 인스턴스 메서드(Instance Method)

소재훈 2022. 2. 11. 20:44

스위프트에서는 클래스, 구조체, 열거형등의 동작을 캡슐화한 인스턴스 메서드

타입 자체의 동작을 수행하는 타입 메서드를 정의할 수 있다.

 

구조체와 열거형이 메서드를 가질 수 있다는 점은 스위프트와 다른 프로그래밍 언어의 차별화된 장점이다.

스위프트는 프로그래머가 정의하는 타입(클래스, 구조체, 열거형 등)에 자유롭게 메서드를 정의할 수 있다.

인스턴스 메서드(instance method)

특정 타입의 인스턴스에 속한 함수를 말한다. 인스턴스와 관련된 동작을 수행한다.

문법은 함수와 동일하다.

인스턴스 메서드는 함수와 달리 특정 타입 내부에 구현하므로, 인스턴스가 존재할 때만 사용할 수 있다는 점이 함수와의 유일한 차이점이다.

class LevelClass {
    //현재 레벨을 저장하는 저장 프로퍼티
    var level: Int = 0 {
        didSet {
            print("Level \(level)")
        }
    }
    
    //레벨이 올랐을 때 호출할 메서드
    func levelUp() {
        print("Level up!")
        level += 1
    }
    
    //레벨이 감소 했을 때 호출할 메서드
    func levelDown() {
        print("Level down!")
        level -= 1
        if level < 0 {
            reset()
        }
    }
    
    func jumpLevel(to: Int) {
        print("Jump to level \(to)")
        level = to
    }
    
    func reset() {
        print("Reset!")
        level = 0
    }
}

var levelClassInstance: LevelClass = LevelClass()
levelClassInstance.levelUp()
//Level up!
//Level 1
levelClassInstance.levelDown()
//Level down!
//Level 1
levelClassInstance.levelDown()
//Level down!
//Level -1
//Reset!
//Level 0
levelClassInstance.jumpLevel(to: 3)
//Jump to level 3
//Level 3

LevelClass의 인스턴스 메서드에 level 인스턴스 프로퍼티의 값을 수정하는 코드가 있다. 

위처럼 클래스에서는 인스턴스의 프로퍼티 값을 수정할 때 크게 신경 쓸 필요가 없지만, 구조체와 열거형 타입은 값 타입이므로 앞에 mutating 키워드를 붙여서 해당 메서드가 인스턴스 내부의 값을 변경한다는 것을 명시해야 한다.

값 타입인 구조체와 열거형 내부의 프로퍼티 값을 메서드에서 수정하려면 메서드에 mutating 키워드를 붙여야 한다.
struct levelStrcut {
    var level: Int = 0{
        didSet {
            print("Level \(level)")
        }
    }
    
    mutating func levelUp() {
        print("Level Up!")
        level += 1
    }
    
    mutating func levelDown() {
        print("Level Down")
        level -= 1
        if level < 0 {
            reset()
        }
    }
    
    mutating func jumpLevel(to: Int) {
        print("Jump to \(to)")
        level = to
    }
    
    mutating func reset() {
        print("Reset!")
        level = 0
    }
}

 

self 프로퍼티

모든 인스턴스는 암시적으로 생성된 self 프로퍼티를 갖는다. 자바의 this처럼 인스턴스 자기 자신을 가리키는 프로퍼티이다. 메서드의 매개변수인지, 인스턴스의 프로퍼티인지 구분하는 등 좀 더 명확히 지정하고 싶을 때 사용한다.

class LevelClass {
    var level: Int = 0
    
    func jumpLevel(to level: Int) {
        print("Jump to \(level)")
        self.level = level
    }
}

 

또한 self 프로퍼티를 이용해서 값 타입 인스턴스 자체의 값을 치환할 수 있다.

클래스의 인스턴스는 참조 타입이므로, self 프로퍼티에 다른 참조를 할당할 수 없지만 구조체나 열거형등은 self 프로퍼티를 사용하여 자신 자체를 치환할 수도 있다.

 

callAsFunction 메서드

사용자 정의 명목 타입의 호출 가능한 값(Callable values of user-defined nominal types)을 구현하기 위해 인스턴스를 함수처럼 호출할 수 있도록 하는 메서드(call-as-function method)가 있다. 

특정 타입의 인스턴스를 문법적으로 함수를 사용하는 것처럼 보이게 할 수 있는데, callAsFunction이라는 이름의 메서드를 구현해 인스턴스를 함수처럼 호출할 수 있다.

struct Puppy {
    var name: String = "댕댕이"
    
    func callAsFunction() {
        print("댕댕~")
    }
    
    func callAsFunction(destination: String) {
        print("댕댕이가 \(destination)으로 갑니다~")
    }
    
    func callAsFunction(something: String, times: Int) {
        print("댕댕이가 \(something)을 \(times)번 반복합니다.")
    }
    
    func callAsFunction(color: String) -> String {
        return "\(color) 응가"
    }
    
    mutating func callAsFunction(name: String) {
        self.name = name
    }
}

var doggy: Puppy = Puppy()
doggy.callAsFunction() //댕댕~
doggy() //댕댕~ -> 인스턴스를 함수처럼 사용하고 있다.
doggy.callAsFunction(destination: "집") //댕댕이가 집으로 갑니다~
doggy(destination: "뒷동산") //댕댕이가 뒷동산으로 갑니다~
doggy(something: "공중제비", times: 3) //댕댕이가 공중제비을 3번 반복합니다.
print(doggy(color: "무지개색")) //무지개색 응가
doggy(name: "멍멍이")
print(doggy.name) //멍멍이

doggy() 표현과 doggy.callAsFunction()은 완전히 똑같은 표현이다.

마찬가지로 doggy(destination: "집")과 doggy.callAsFunction(destination: "집")은 완전히 동일한 표현이 된다.

 

하지만 호출하는 것 외에 타입처럼 함수 표현으로는 사용할 수 없음에 주의하자.

let function: (String) -> Void = doggy(destination:) //불가능
let function: (String) -> Void = doggy.callAsFunction(destination:) //가능