Apple 제공 Swift 프로그래밍 가이드(3.0.1)의 Methods 부분을 공부하며 정리한 글입니다. 개인적인 생각도 조금 들어가있습니다.
들어가며
메서드(method)란 특정 타입에 연관된 함수(function)를 말한다. 클래스, 구조체, ENUM은 인스턴스 메서드와 타입 메서드(Objective-C에서의 클래스 메서드)를 정의할 수 있다.
Swift에서는 구조체와 ENUM 안에도 메서드를 정의할 수 있다는 것이 C, Objective-C와의 주요 차이점이라고 할 수 있다.
Instance Methods
인스턴스 메서드는 특정 클래스, 구조체, ENUM의 인스턴스에 속하는 메서드이다. 함수와 같은 문법을 사용한다.
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
let counter = Counter() // 0
counter.increment() // 1
counter.increment(by: 5) // 6
counter.reset() // 0
참고로 함수 단원에서 배웠던 parameter name, argument label 의 규칙이 메서드에도 동일하게 적용된다. (메서드는 "타입에 연관된 함수"임)
<The self Property>
모든 인스턴스는 self 라는 프로퍼티를 가진다. 인스턴스 자신을 가리키는 참조이다. self 프로퍼티는 인스턴스 메서드내에서 현재 자신(인스턴스)을 참조할 때 쓰일 수 있다.
func increment() {
// 이런 식으로
self.count += 1
}
그러나 딱히 self를 쓰지 않더라도 인스턴스 메서드 안에서 변수/상수 이름을 사용하면 self 내의 변수/상수임을 가정해주므로 별로 쓸 일은 없다. 그러나 메서드의 파라미터 이름과 인스턴스 프로퍼티 이름이 겹칠 경우에는 써야 한다.
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
}
}
<Modifying Value Types from Within Instance Methods>
값 타입의 프로퍼티는 인스턴스 메서드 안에서 값을 그냥은 변경할 수가 없다. 값 타입인 구조체와 ENUM의 인스턴스 메서드 안에서 프로퍼티의 값을 변경하려면 꼭 mutating 라는 키워드를 메서드 앞에 붙여야 한다.
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY:Double) {
x += deltaX
y += deltaY
// mutating function 이기 때문에 성공
}
}
var somePoint = Point(x: 1.0, y: 1.0) // (1.0, 1.0)
somePoint.moveBy(x: 2.0, y: 3.0) // (3.0, 4.0)
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0) // compile error
// mutating 메서드는 let으로 선언된 인스턴스에서 사용불가
<Assigning to self Within a Mutating Method>
mutating 메서드에서 self 자체에 새로운 인스턴스를 대입하면 인스턴스 자체에 새로운 인스턴스를 할당 가능하다.
// struct의 경우
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)
}
}
// enum의 경우
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 is now equal to .high
ovenLight.next()
// ovenLight is now equal to .off"
위와 같이 인스턴스 메서드 내에서 self에 할당을 하는 것은 값타입인 구조체/ENUM만 가능하다. 클래스의 경우 mutating 메서드 자체를 정의할 수 없으며 (할 필요가 없으며) 클래스의 인스턴스 메서드 안에서 self에 할당을 하려고 하면 self는 immutable이라며 에러가 난다.
Type Methods
Objective-C에서의 클래스 메서드같이 타입 그 자체에 속하는 메서드이다.
문법은 타입 프로퍼티와 유사하다. 메서드 앞에 static 키워드를 붙여서 정의한다. 클래스의 타입 메서드의 경우 static 대신 class 키워드를 붙이면, 서브클래스에게 해당 타입 메서드의 오버라이드를 허락할 수 있다. (반대로 붙이지 않으면 오버라이드 불가)
<note> Objective-C에서는 타입 레벨의 메서드를 오직 Objective-C Class에만 정의할 수 있었다. 그러나 Swift에서는 타입 레벨의 메서드를 모든 클래스, 구조체, ENUM에 정의할 수 있다.
class SomeClass {
static func someTypeMethod() {
}
class func someOverridableTypeMethod() {
}
}
class SomeChildClass: SomeClass {
override static func someTypeMethod() {
// compile error
}
override class func someOverridableTypeMethod() {
// OK
}
}
SomeClass.someTypeMethod() // 호출은 이렇게 타입에 대고 한다
타입 메서드 안에서는 자기 타입에 정의된 다른 타입 프로퍼티나 타입 메서드를 참조할 때 타입 이름을 쓰지 않아도 된다. (인스턴스 메서드 안에서도 self를 명시하지 않아도 알아서 self 내의 프로퍼티를 찾아주는 것과 동일한 원리이다. 타입 메서드 안에서의 self는 어차피 타입 그 자체이기 때문에)
struct LevelTracker {
static var highestUnlockedLevel = 1
static func unlock(_ level: Int) {
if level > highestUnlockedLevel {
highestUnlockedLevel = level
// LevelTracker.highestUnlockedLevel 로 접근하지 않아도 된다는 것
}
}
}
'Swift 공식 가이드 > Swift 3' 카테고리의 다른 글
Inheritance (0) | 2017.03.01 |
---|---|
Subscripts (0) | 2017.03.01 |
Properties (0) | 2017.02.27 |
Classes and Structures (0) | 2017.02.27 |
Enumerations (0) | 2017.02.27 |