메소드는 일종의 함수로서 클래스나 구조체, 열거형과 같은 객체 내에 함수가 선언될 경우 이를 메소드라고 통칭한다. 즉 메소드는 특정 타입의 객체 내부에서 사용하는 함수라고 할 수 있다. 함수와 메소드의 차이점은 구현 목적이 가지는 독립성과 연관이 있다. 함수는 독립적인 기능 구현을 위해 만들어지지만, 메소드는 하나의 객체 내에 정의된 다른 메소드들과 서로 협력하여 함수적 기능을 수행한다.
메소드는 인스턴스 메소드와 타입 메소드로 구분되는데, 인스턴스를 생성해야 사용할 수 있는 메소드가 인스턴스 메소드, 객체의 인스턴스를 생성하지 않아도 사용할 수 있는 메소드가 타입 메소드이다.
인스턴스 메소드
인스턴스 메소드는 클래스, 구조체 또는 열거형과 같은 객체 타입이 만들어내느 인스턴스에 소속된 함수이다. 인스턴스 메소드는 객체 타입 내부에 선언된다는 점을 제외하고는 일반 함수와 선언하는 형식이 완전히 동일하다. 인스턴스 메소드는 구조체나 클래스, 열거형 등의 객체 타입을 인스턴스화 한 후, 이 인스턴스를 통해 호출한다.
struct Resolution {
var width = 0
var height = 0
// 구조체에 요약된 설명을 리턴해주는 인스턴스 메소드
func desc() -> String {
let desc = "이 해상도는 \(self.width) X \(self.height)로 구성 된다."
return desc
}
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
// 클래스의 요약된 설명을 리턴해주는 인스턴스 메소드
func desc() -> String {
if self.name != nil {
let desc = "이 \(self.name!) 비디오 모드는 \(self.frameRate)의 프레임 비율로 표시된다."
return desc
} else {
let desc = "이 비디오 모드는 \(self.frameRate)의 프레임 비율로 표시된다."
return desc
}
}
}
여기서 desc() 라는 메소드가 선언되어 있다. 메소드는 일반 함수와 세 가지 항목에서 차이가 있다.
- 구조체와 클래스의 인스턴스에 소속된다는 점
- 메소드 내에서 정의된 변수와 상수뿐만 아니라 클래스 범위에서 정의된 프로퍼티도 모두 참조할 수 있다는 점
- self 키워드를 사용할 수 있다는 점
프로퍼티 앞에 붙은 self 키워드는 클래스나 구조체의 인스턴스 자신을 가리킨다. 즉 self.width는 클래스나 구조체 자신의 인스턴스에 속한 width 프로퍼티라는 의미이다. 인스턴스는 클래스 외부에서 접근할 뿐, 클래스 내부에서는 어느 인스턴스에 할당될 것인지에 대한 정보를 정확히 알 수 없다. 이 때문에 인스턴스 이름 대신 self라는 키워드를 사용하여 자기 자신의 인스턴스라는 것을 표현하는 것이다.
스위프트 컴파일러는 self를 붙이지 않은 변수가 프로퍼티라는 것을 대부분 잘 인지하여 처리한다. 하지만 반드시 self를 붙여주어야 할 때가 있는데, 메소드 내부에 프로퍼티와 동일한 이름을 가진 변수나 상수가 선언되었을 때이다. 이름만으로는 프로퍼티와 일반 변수를 구분할 수 없어 이를 구별하기 위해 사용된다. 즉 프로퍼티와 일반 변수 이름이 충돌할 때 프로퍼티 앞에 반드시 self 키워드를 붙여야 한다.
struct Resolution {
var width = 0
var height = 0
func judge() -> Bool {
let width = 30
return self.width == width
} // false
}
judge() 메소드는 프로퍼티 width와 메소드 내부 width 변수의 값을 비교하므로 결과는 false이다. 아래는 또 다른 예제이다.
class Counter {
// 카운트를 저장할 프로퍼티
var count = 0
// 카운트를 1 증가
func increment() {
self.count += 1
}
// 입력된 값만큼 카운트를 증가
func incrementBy(amount: Int) {
self.count += amount
}
// 카운트를 0으로 초기화
func reset() {
self.count = 0
}
}
인스턴스 메소드를 호출할 때는 인스턴스 프로퍼티를 참조할 때와 마찬가지로 점 구문을 사용하여 호출한다. 인스턴스를 할당한 상수 또는 변수와 메소드 사이에 점을 사용하여 연결한다.
// Counter 클래스의 인스턴스를 생성한다. 초기 카운터의 값은 0이다
let counter = Counter()
// 카운터 값을 증가시킨다. 이제 카운터 값은 1이다.
counter.increment()
// 카운터 값을 5만큼 증가시킨다. 이제 카운터 값은 6이다.
counter.incrementBy(amount: 5)
// 카운터 값을 초기화 한다. 이제 카운터 값은 0이다.
counter.reset()
위 코드를 이해하는 데는 어렵지 않다. 주의할 점은 구조체나 열거형의 인스턴스 메소드 내부에서 프로퍼티의 값을 수정할 때는 반드시 메소드 앞에 mutating이라는 키워드를 추가해야 한다. 이 키워드를 추가하지 않고 값을 변경하고자 하면 오류가 발생한다. 아래는 예제이다.
struct Point {
var x = 0.0
var y = 0.0
mutating func moveByX(x deltaX: Double, y deltaY: Double) {
self.x += deltaX
self.y += deltaY
}
}
var point = Point(x: 10.5, y: 12.0)
point.moveByX(x: 3.0, y: 4.5)
print("이제 새로운 좌표는 (\(point.x), \(point.y))입니다.")
// 실행 결과
// 이제 새로운 좌표는 (13.5, 16.5)입니다.
이와 달리 클래스의 인스턴스 메소드에는 프로퍼티를 수정할 때 별도의 키워드를 필요로 하지 않는다.
class Location {
var x = 0.0
var y = 0.0
func moveByX(x deltaX: Double, y deltaY: Double) {
self.x += deltaX
self.y += deltaY
}
}
var loc = Location()
loc.x = 10.5
loc.y = 12.0
loc.moveByX(x: 3.0, y: 4.5)
print("이제 새로운 좌표는 (\(loc.x), \(loc.y))입니다.")
// 실행 결과
// 이제 새로운 좌표는 (13.5, 16.5)입니다.
타입 메소드
인스턴스를 생성하지 않고 객체 타입 자체에서 호출할 수 있는 메소드를 타입 메소드라고 한다. 타입 메소드도 타입 프로퍼티와 동일하게 구조체나 열거형, 클래스 모두 타입 메소드를 선언할 때는 static 키워드를 사용한다. 반면 하위 클래스에서 재정의 가능한 타입 메소드를 선언할 때는 class 키워드를 사용한다. 물론 이 키워드는 클래스 타입에서만 사용이 가능하다. 아래는 예제 코드이다.
class Foo {
// 타입 메소드 선언
class func fooTyopeMethod() {
// 타입 메소드 구현 내용
}
}
let f = Foo()
f.fooTyopeMethod() // 오류
Foo.fooTyopeMethod()
타입 메소드를 사용할 때 주의점이 있다. 타입 메소드는 객체 타입 전체에 영향을 미친다. 이런 영향 범위를 고려하여 사용해야 한다. 또한 타입 메소드는 인스턴스 프로퍼티를 참조할 수 없다. 타입 메소드 자체에 인스턴스가 존재하지 않기 때문이다.
'swift' 카테고리의 다른 글
| 스위프트 타입 캐스팅 (1) | 2024.04.16 |
|---|---|
| 스위프트 상속 (1) | 2024.04.16 |
| 스위프트 프로퍼티 (0) | 2024.04.15 |
| 스위프트 구조체와 클래스 (0) | 2024.04.15 |
| 스위프트 클로저 (0) | 2024.04.12 |