객체지향 프로그래밍 언어에 익숙하다면 현재의 클래스 인스턴스에 속한 메서드나 프로퍼티를 가리킬 때 프로퍼티와 메서드 앞에 self를 붙이는 습관이 있을 것이다. 스위프트 언어 역시 그렇게 사용하기 위한 self 프로퍼티 타입을 제공한다. 따라서 다음은 완벽하게 유효한 코드다.
class MyClass { var myNumber = 1 func addTen() { self.myNumber += 10 // 해당 클래스 인스턴스에 속한 myNumber에 접근 } } - 위의 코드에서 self는 클래스 인스턴스에 속한 myNumber 이라는 이름의 프로퍼티를 참조한다는 걸 컴파일러에게 알려준다. 하지만 대부분의 경우엔 self를 사용할 필요가 없다.
- 왜냐하면 self는 프로퍼티와 메서드에 대한 참조를 디폴트로 간주하기 때문이다.
- 위의 코드에서 self를 생략해서 작성해보자.
class MyClass { var myNumber = 1 func addTen() { myNumber += 10 // self 생략했다 } } - 대부분의 경우 스위프트에서 self는 선택적으로 사용된다. self를 사용해야 하는 상황은 프로퍼티나 메서드를 클로저 표현식 내에서 참조할 경우다. 예를 들어, 다음의 클로저 표현식에서는 반드시 self를 사용해야 한다.
document?.openWithCompetionHandler({(success: Bool) -> Void in if success { self.ubiquityURL = resultURL } }) - 또한, 함수의 매개변수가 클래스 프로퍼티와 동일한 이름을 가질 경우와 같이 코드의 모호성을 해결하기 위해 self를 사용해야 한다. 예를 들어, 다음 코드에서 첫 번째 print 구문은 myNumber 매개변수를 통해 함수에 전달된 값을 출력하겠지만, 두 번째 print 구문은 myNumber라는 클래스 프로퍼티에 할당된 값을 출력한다.
class MyClass { var myNumber = 10 // 클래스 프로퍼티 func addTen(myNumber: Int) { print(myNumber) // 함수의 매개변수 값을 출력 print(self.myNumber) // 클래스 프로퍼티 값을 출력 } } [!note] 느낌은 온다. 근데 확 이해되는 느낌이 아니다. 어지럽다. 지피티를 통해 한 번 더 이해하고 가자.
내가 헷갈리는 포인트
- 어떨 때 쓰고 어떨 때 생략하지?
- 클로저 안에서 왜 꼭 self를 써야 하지?
self: 지금 이 클래스의 인스턴스에 있는 프로퍼티라는 뜻을 가진다.
대부분의 경우 self는 생략 가능하다
class MyClass { var myNumber = 1 func addTen() { myNumber += 10 // self 없어도 문제 없음 } } - 여기서 myNumber라고 쓰면, Swift는 자동으로 "아, 이건 이 클래스 안의 프로퍼티를 말하겠구나?"하고 알아듣는다 . 왜냐, 함수 안에 동일한 이름의 매개변수나 지역변수가 없기 때문이다.
- 근데 이름이 겹치면?
func update(myNumber: Int) { print(myNumber) // 매개변수 print(self.myNumber) // 클래스 속성 } - 이 경우엔 이름이 겹치기 때문에 누굴 가리키는지 명확히 해줘야 한다.
클로저 안에서는 항상 self를 써야 하는 이유
[[0805-2 클로저]]
someFunction { self.doSomething() } 클로저는 캡쳐라는 메커니즘을 통해 바깥 변수를 저장해서 나중에 사용한다. 그래서 Swift는 "이건 외부 인스턴스를 참조하는구나"를 명확히 하기 위해 self를 강제로 쓰게 한다.
class TimerClass { var count = 0 func start() { Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in self.count += 1 print("카운트: \(self.count)") } } } - 여기서 클로저는 비동기적으로 실행된다.
- 근데 만약 self.count += 1 에서 self를 생략하면, Swift는 헷갈린다.
- 그래서 Swift는 "클로저 안에서 self 쓰려면 명시적으로 써!" 라고 강제한다.
시각적으로 표현하면
class Dog { var name = "Coco" func rename(name: String) { print(name) // 매개변수 print(self.name) // 클래스 속성 } } 너가 넘겨준 이름은 name이고, 이 인스턴스 안에 있는 원래 이름은 self.name이야.
self는 생략할 수 있어도, 의도를 명확히 보이게 쓰기도 한다
- 예를 들어, 협업시에 self.name = name 이런 식으로 쓰면 "아 이건 외부에서 받은 값을 내 클래스 프로퍼티에 할당하는구나"를 한 눈에 볼 수 있게 된다.