[Swift] 메소드 (Method)

특정 타입과 관련된 혹은 가지고 있는 함수를 메소드라고 합니다

타입과 관련되있으니 클래스, 구조체, 열거형은 메소드를 가질 수 있겠죠?

오늘은 이 메소드에 대해 천천히 씹어서 삼켜보도록 합시다!

인스턴스 메소드

인스턴스 프로퍼티와 마찬가지고 인스턴스에 속해 있는, 연결된 메소드를 인스턴스 메소드라고 합니다.

이 인스턴스 메소드 안에서는 다른 인스턴스 프로퍼티와 인스턴스 메소드에 접근하고 호출할 수 있습니다.

인스턴스라는 같은 그룹내에 묶여 있으니 당연하겠죠?

Self

다른 개발자들의 코드 혹은 예제 코드들을 보면 인스턴스 메소드 내에서 사용되는 self를 꽤나 자주 접할 수 있는데요

요 self라는 프로퍼티는(가이드북에서 프로퍼티라고 하네요?) 인스턴스 그 자체인 프로퍼티라고 합니다.

즉 인스턴스 메소드 내에서 자기 자신 인스턴스를 참조할 수 있는 프로퍼티라는 말입니다.

코드로 보면 쉽게 이해가 될꺼에요

class SomeClass() {
    var instanceName: String
    init(_ name: String) {
        instanceName = name
        print(self.instanceName)
    }	
}

let a = SomeClass("a")
// a
let b = SomeClass("b")
// b

a,b는 SomeClass 타입의 인스턴스들 입니다.

인스턴스 생성 시 init이 호출되고 그 안에서 self.instanceName이 호출되는걸 볼 수 있죠

바로 자기 자신의 instanceName 프로퍼티를 호출하는 걸 볼 수 있습니다

이 self 프로퍼티는 보통의 경우 생략하여도 현재 인스턴스의 프로퍼티명과 메소드명을 자동으로 참조 하게 되지만

아래의 코드를 봐봅시다

class SomeClass() {
    var name: String
    init(_ name: String) {
        self.name = name
    }
}

인스턴스의 프로퍼티명과 매개변수명이 같습니다.

이런 경우 Swift는 매개변수의 이름을 우선으로 인식하기 때문에 self를 사용하여 인스턴스 프로퍼티명을 말하는 거라고 명확하게 알려줘야 합니다!

값 타입에서의 인스턴스 메소드

구조체, 열거형은 값 타입이며 값 타입은 전달을 받거나 할당을 할 때 복사가 되어진다고 학습하였습니다!

잘 모르신다면 여기를 참고해주세요!

그런 이유 때문인지 값 타입의 인스턴스 메소드에서는 인스턴스 프로퍼티를 수정하지 못합니다!

인스턴스 메소드 내에서 인스턴스 프로퍼티를 접근 할 때 값 타입의 인스턴스 자체를 복사하여 접근한다고 합니다.

그래서 그 복사본의 프로퍼티를 수정하면 원본과 이미 같지 않기 때문에 ( 복사본을 수정해봤자 어차피 원래 프로퍼티는 그대로 겠죠?)

수정할 수 없는 거겠죠

struct SomeStruct {
	var someProperty: Int = 5
	func someMethod() {
		someProperty = 3 // Cannot assign to property: 'self' is immutable 에러
	}
}

이 코드를 예로 들면 메소드 내에서 사용되고 있는 someProperty는 인스턴스 프로퍼티가 아닌

인스턴스 프로퍼티인 someProperty 값을 복사한 복사본이란 거죠.

아니 그럼 방법이 없는거야?

당연히 있으니까 이렇게 길게 설명을 하는거겠죠? func 키워드 앞에 mutating 키워드를 붙여 주면 됩니다!

이 mutating 키워드를 붙이면 해당 메소드는 암시적인 self(인스턴스 그 자체)에 수정된 프로퍼티가 적용된 새로운 인스턴스를 만들어 두고 메소드가 종료되면 새로 만들어진 인스턴스로 기존 인스턴스를 대체하게 됩니다.

어디선가 본 거 같지 않나요? 네 바로 inout의 동작방식과 매우 같습니다! 실제로 컴파일러가 매개변수로 self를 비밀리에 넘겨서 메소드를 동작시키는데

(inout에 대해 가물가물 하거나 모르신다면 여기를 참고 해주세요?)

쓰다 보니 문득 생각난건데 그래서 self를 생략해도 메소드 내에서 인스턴스 프로퍼티명을 사용할 수 있는건가 싶네요

mutating 키워드를 붙이면 self에 inout을 붙여서 전달한다고 합니다.

struct SomeStruct {
    var someProperty: Int = 5
    mutating func someMethod() {
        someProperty = 3 
    }
}

var mStruct = SomeStruct()
print(mStruct.someProperty) // 5
mStruct.someMethod()
print(mStruct.someProperty) // 3

성공적으로 수정 됩니다!

Mutating 메소드에 self 할당

제목이 거창하죠?

별거 없습니다 위의 코드에서 컴파일러가 자동으로 처리해준걸 개발자가 직접 할 수 있단 소리죠

무슨 소리냐?

코드로 보시죠!

struct SomeStruct {
    var someProperty: Int = 5
    mutating func someMethod() {
        self = SomeStruct(someProperty: 3)
    }
}

var mStruct = SomeStruct()
print(mStruct.someProperty) // 5
mStruct.someMethod()
print(mStruct.someProperty) // 3

말 그대로 self에 새로운 인스턴스를 생성할 수 있다! 이거죠

ㅇㅋ 알았어 이게 그럼 왜필요 한대? 하고 생각이 들 무렵,

애플의 가이드북의 유용한 예제를 하나 제공해주었습니다.

enum StateSwitch {
    case off, low, high

    mutating func next() {
        switch self {
        case .off:
            self = .low 
        case .low:
            self = .high
        case .high:
            self = .off
        }
    }
}

var test = StateSwitch.off
test.next() // .low
test.next() // .high

메소드 하나로 스텝을 단계별로 이동시킬 수 있습니다!

타입 메소드

인스턴스가 만들어져야 사용할 수 있는 인스턴스 메소드와 달리

타입 자체에 속한 메소드를 타입 메소드라고 합니다 ( 타입 프로퍼티와 같은 개념이죠)

타입 프로퍼티와 마찬가지로 static 키워드를 사용하며 func 키워드 앞에 붙여주어 사용합니다

물론 클래스 타입의 경우엔 class 키워드를 사용해 상속 받는 클래스가 재정의(override)하여 사용할 수 있게 해줄 수도 있습니다.

타입 메소드에서 사용하는 self는 인스턴스가 아니라 타입 자체를 말합니다.

타입 메소드 안에서는 다른 타입 메소드, 타입 프로퍼티를 사용할 때 타입.프로퍼티, 타입.메소드가 아니라

그냥 프로퍼티명과 메소드명만 사용할 수 있습니다!

class SomeClass {
    static var name = "SweetFood"
// SomeClass.name이 아닌 name 호출
    static func getName() -> String { name } 
// SomeClass.getName()이 아닌 getName() 호출
    static func printName() { print(getName()) }
}

SomeClass.printName()
// SweetFood

정리

  1. 인스턴스 메소드는 인스턴스에 속한(연결된) 메소드다
  2. 값 타입의 메소드에서 프로퍼티를 수정하기 위해선 mutating 키워드를 사용한다
  3. 타입 메소드는 타입 자체에 속한 메소드이다
  4. self는 인스턴스 메소드 에서는 인스턴스를 참조, 타입 메소드 내에서는 타입 그 자체를 말한다

카테고리:

업데이트:

댓글남기기