카테고리 없음

Swift Deep Dive: Instance Method & Type Method

여의도사노비 2023. 3. 8. 23:58
728x90

가끔 개발 용어 중 나의 머리 속에 추상적으로 존재하고 있는 개념들이 있다.

오늘 나오는 이 둘 모두 그렇다... 인스턴스 메서드와 타입 메서드...! 이 둘에 대해서 조금 딥하게 알아보고자 한다.


메서드부터 시작하자

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/methods/

 

Documentation

 

docs.swift.org

공식 문서는 Method에 대한 정의로 시작한다. 

🤖 인스턴스 혹은 타입에 속하는 함수들을 정의하고 호출하는 것.

 

🙋🏻‍♂️ 이런 개념에 입각한 용어는 암기하고 떠올리기가 어렵다. 그래서 우리는 보통 클래스, 스트럭트 등에 정의 되어있는 함수를 통틀어 메서드라고 부른다. 실제로 Docs에서 정의하고 있는 표현과 크게 다르지는 않다.

 

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, structures, and enumerations can also define type methods, which are associated with the type itself. Type methods are similar to class methods in Objective-C.

The fact that structures and enumerations can define methods in Swift is a major difference from C and Objective-C. In Objective-C, classes are the only types that can define methods. In Swift, you can choose whether to define a class, structure, or enumeration, and still have the flexibility to define methods on the type you create.

 

🤖 Swift 내의 메서드는 두 가지 종류가 있다. Instance Method, Type Method.

메서드는 특정 타입들과 관련이 있는 함수이다. 클래스, 구조체, 열거형은 모두 주어진 타입의 인스턴스와 작용할 수 있도록 캡슐화된 인스턴스 메서드를 선언할 수 있다. 또한 클래스, 구조체, 열거형은 타입 그 자체와 연관된 타입 메서드도 선언할 수 있다. 타입 메서드는 objc의 클래스 메서드(Class Method)와 비슷하다.

 

🤖 Swift에서는 구조체와 열거형이 메서드를 선언할 수 있다는 점이 C && objc와 가장 큰 차이다. objc에서는 클래스가 메서드를 선언할 수 있는 유일한 타입이다. Swift에서는 클래스를 선택하든, 구조체를 선택하든, 열거형을 선택하든 여전히 메서드를 선언할 수 있는 다양한 방법이 있다.

 

🙋🏻‍♂️ 와 이거 어지럽다. 위의 내용에 따르면 인스턴스 메서드타입 메서드 둘다 클래스, 구조체, 열거형에서 선언할 수 있다. 그리고 타입 메서드는 objc에 나오는 클래스 메서드와 비슷하다는 것이다. 클래스 메서드가 뭔데...? 싶어서 찾아보니

 

A class method is a method that operates on class objects rather than instances of the class. In Objective-C, a class method is denoted by a plus (+) sign at the beginning of the method declaration and implementation:

 

Apple의 공식 홈페이지에 따르면, 클래스 메서드는 클래스의 인스턴스가 아닌 클래스 객체에 작용하는 메서드이다. 솔직히 100프로 이해는 안가지만 연관성은 이제 알겠다. 위에서 타입 메서드는 objc의 클래스 메서드와 비슷하다고 했다. 아마 이 타입 메서드도 인스턴스가 아닌 타입 그 자체와 연관이 있기 때문에 둘이 비슷하다고 말한 것이다.

 

일단 여기까지 인스턴스 메서드, 타입  메서드 그리고 클래스 메서드라는게 있다는 것만 알고 넘어가보자.


인스턴스 메서드(Instacne Method)를 알아보자

 🙋🏻‍♂️ 이 부분부터는 공식 문서를 참고했지만 하나하나 해석하기엔 양이 너무 많아 나의 직역 의역 오역을 기록해본다.

인스턴스 메서드는 특정 유형의 인스턴스에 속하는 메서드이며 해당 유형의 인스턴스에서만 호출할 수 있다. Swift에서 인스턴스 메서드를 정의하려면 먼저 메서드가 속한 클래스, 구조 또는 열거형 내에서 메서드를 선언해야 한다.

 

예를 들면 이렇다.

class MyClass {
    func myMethod() {
        // Code for the method goes here
    }
}

let myObject = MyClass()
myObject.myMethod()

myMethod는 MyClass 클래스의 메서드이며 myMethod 메서드를 호출하기 위해선 MyClass의 인스턴스인 myObject를 선언하고 이를 통해 접근해야한다.

 

또한 인스턴스 메서드는 함수처럼 파라미터(매개변수)를 갖고 값을 반환할 수 있고, 인스턴스의 속성 및 기타 인스턴스 메서드에 접근하고 수정할 수 있다.


이번에도 예를 들면 이렇다.

class Car {
    var speed: Double = 0.0
    
    func accelerate(amount: Double) {
        speed += amount
    }
    
    func brake() {
        speed = max(0, speed - 10)
    }
}

let myCar = Car()
myCar.accelerate(amount: 20.0)
print(myCar.speed) // Output: 20.0
myCar.brake()
print(myCar.speed) // Output: 10.0

accelerate 메서드는 amount라는 더블 타입의 파라미터를 갖고 있고 이를 통해 speed의 값에 영향을 미친다. accelerate 메서드 뿐만 아니라 brake 메서드도 speed 속성에 영향을 미치는 모습을 볼 수 있다.


타입 메서드(Type Method)를 알아보자

🙋🏻‍♂️ 위에서도 나왔듯이 인스턴스 메서드와는 다르게 타입 메서드는 인스턴스 없이도 접근이 가능하다.

타입 메서드는 Static을 이용하여 선언할 수 있다. 아까 타입 메서드와 클래스 메서드가 비슷한 역할을 한다고 했는데 클래스 메서드는 Class를 func앞에 붙임으로써 선언 가능하다. 이 둘이 계속 함께 언급되는 이유는 거의 인스턴스 없이 타입 자체 메서드에 바로 접근이 가능하다는 공통점을 지니고 있지만, override의 가능 여부에 큰 차이가 있기 때문이다. Static의 경우 override가 불가능하고, Class의 경우 override가 가능하다. 

 

class Animal {
    class func makeNoise() {
        print("Animal is making noise")
    }
    
    static func makeNoise2() {
        print("Animal is making noise2")
    }
}

class Dog: Animal {
    override class func makeNoise() {
        super.makeNoise()
        print("Dog is barking")
    }
    
    override static func makeNoise2() {
        super.makeNoise2()
        print("Dog is barking2")
    }
}

Animal.makeNoise() // "Animal is making noise"
Dog.makeNoise() // "Animal is making noise" followed by "Dog is barking"

위의 코드를 보면 Animal 클래스를 상속받은 Dog 클래스에서 makeNoise() 클래스 메서드는 슈퍼클래스의 클래스 메서드를 오버라이드하여 새로운 print문을 추가할 수 있다. 하지만 static 메서드의 경우 상속이 거부된다는 오류가 뜬다. 따라서 같은 접근 방식을 취하지만 상속받을 일이 없는 경우에는 static, 상속 받을 일이 필요한 경우 class 메서드를 활용하게된다.

 

class MyClass {
    static func myStaticMethod() {
        print("This is a static method in MyClass.")
    }
}

class MySubclass: MyClass {
    static func mySubclassStaticMethod() {
        print("This is a static method in MySubclass.")
        MyClass.myStaticMethod() // Call the static method in the superclass directly
    }
}

MySubclass.mySubclassStaticMethod()

// This is a static method in MySubclass.
// This is a static method in MyClass.

static 메서드는 상속을 받지 못하지만 이렇게 슈퍼클래스의 함수를 직접 가져와서 활용할 수 있다. 


Static Method를 조금 더 구체적인 상황에서 사용해보자

아래는 Swift 공식문서에 나오는 코드이다.

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

코드에 대한 상황 설명으로 게임을 예를 들고 있는데... 결국 static 메서드는 게임의 전체에 영향을 끼치는 함수라는 것이 중요하다. 게임 내에 싱글 플레이어가 여러 캐릭터를 활용할 수 있는데, 이때 내가 unlock한 게임레벨이 나의 다른 캐릭터들의 세계관에까지 영향을 미친다는 것이다. 즉, 유일한 값을 가져아하는 상황이라고 생각할 수 있겠다.

 

사실 Type 메서드(Static 메서드)와 Class 메서드... 이 두가지 개념안에 존재하는 연관된 여러가지 개념이 너무 많아서 한 번에 전부 이해하기 쉽지 않다. 정리하면서도 전체적인 뼈대는 잡았지만 딥 다이브라고 하기엔 상당히 부족함을 느꼈다. 다른 개념을 공부해나가면서 연계적으로 고민해봐야할 주제인 것 같다.


타입 메서드에 대한 TMI

  1. 타입 메서드는 유틸리티 함수(프로그램을 개발하는 과정에서 자주 사용되는 기능을 함수로 구현한 것)를 만드는데 종종 사용된다. 예를들면 절대값을 구할 수 있는 abs() 같은 함수가 타입 메서드로 이루어져있다. abs()는 Numeric 프로토콜의 타입 메서드이다.
  2. 타입 인스턴스의 초기화나 타입 인스턴스를 쉽게 만들 수 있도록 돕기도 한다. 예를들면 Date()도 Date class의 타입 메서드이다.

Reference