본 내용은 스위프트 프로그래밍 3판 (야곰 지음) 교재를 공부한 내용을 바탕으로 작성 하였습니다.
스위프트에서 메서드
는 클래스, 구조체, 열거형 등에 관련된 함수인 인스턴스 메서드
와 타입 자체에 관련된 함수인 타입 메서드
가 있다.
인스턴스 메서드
는 위에서 간단히 설명한대로 인스턴스 내부에서 인스턴스에 관련된 값을 변경하거나 연산을 수행하는 기능을한다. 인스턴스 내부에서 구현하므로 인스턴스 생성시 메서드 호출이 가능하며, 형태는 일반적인 함수의 형태와 유사하다.
다음은 클래스에서 인스턴스 메서드
를 사용하여 계산기 로직을 구현한 코드이다.
class CalculateClass {
var result: Int = 0 {
didSet {
print("result: \(result)")
}
}
//메서드
func add(_ a: Int, _ b: Int) {
result = a + b
}
func sub(_ a: Int, _ b: Int) {
result = a - b
}
func mul(_ a: Int, _ b: Int) {
result = a * b
}
func div(_ a: Int, _ b: Int) {
if b == 0 {
print("0으로 나눌 수 없습니다.")
}
else {
result = a / b
}
}
}
var calculator1: CalculateClass = CalculateClass()
calculator1.add(5, 2)
calculator1.sub(5, 2)
calculator1.mul(5, 2)
calculator1.div(5, 2)
다음은 구조체에서 인스턴스 메서드
를 사용하여 계산기를 구현하였다.
구조체에서의 인스턴스 메서드
의 차이는 위의 코드에서는 각 인스턴스 메서드
의 결과로 result
프로퍼티의 값이 바뀌었는데, 구조체와 같은 값 타입에서는 인스턴스 내부의 변화가 생기는 경우 인스턴스 메서드
앞에 mutating
키워드를 사용하여 내부 프로퍼티 값에 변화가 있다는 것을 명시 하여야 한다.
아래의 코드를 살펴보자
struct CalculateStruct {
var result: Int = 0 {
didSet {
print("result: \(result)")
}
}
//메서드
mutating func add(_ a: Int, _ b: Int) {
result = a + b
}
mutating func sub(_ a: Int, _ b: Int) {
result = a - b
}
mutating func mul(_ a: Int, _ b: Int) {
result = a * b
}
mutating func div(_ a: Int, _ b: Int) {
if b == 0 {
print("0으로 나눌 수 없습니다.")
}
else {
result = a / b
}
}
}
var calculator2: CalculateStruct = CalculateStruct()
calculator2.add(5, 2)
calculator2.sub(5, 2)
calculator2.mul(5, 2)
calculator2.div(5, 2)
스위프트의 타입 메서드
는 다른 객체 지향 언어(예: Java)에서의 static 메서드(클래스 메서드)와 비슷하나 약간 다른 개념으로 사용된다.
스위프트에서의 타입 메서드
는 타입 자체에서 호출이 가능한 메서드이다.
클래스 타입에서 타입 메서드
는 static 키워드
와 class 키워드
를 사용하여 선언 할 수 있는데 클래스의 가장 큰 특징 중 하나인 상속
에서 static 키워드
로 정의한 타입 메서드
는 재정의가 불가능하지만 class 키워드
로 선언한 메서드는 재정의가 가능하다.
다음은 타입 메서드
에 관한 간단한 예시이다.
class AClass {
static func staticTypeMethod() { //static 타입 메서드
print("AClass staticTypeMethod")
}
class func classTypeMethod() { //class 타입 메서드
print("AClass classTypeMethod")
}
}
class BClass: AClass { //상속
//class 타입 메서드 재정의
override class func classTypeMethod() {
print("BClass classTypeMethod")
}
}
AClass.staticTypeMethod()
AClass.classTypeMethod()
BClass.classTypeMethod()
BClass 클래스는 AClass를 상속 받아 class 키워드
로 선언한 타입 메서드
를 재정의 한 것을 볼 수 있다.
스위프트의 self
프로퍼티는 자바의 this
와 유사한 개념이다.
인스턴스 메서드
에서 self
를 사용할 경우 이때 self
는 인스턴스 자체를 의미한다.
하지만 타입 메서드
에서 self
를 사용할 경우 self
는 타입 자체를 의미한다.
다음에서 타입 메서드
에서 self 프로퍼티
를 사용한 예시를 살펴 보자
struct PhotoSize {
static var size: Int = 100
static func zoomIn() {
self.size = 200 //self -> PhotoSize
}
}
class Photo {
var originalSize: Int = 100
func enlarge() {
PhotoSize.zoomIn()
}
func reset() {
PhotoSize.size = self.originalSize //self -> 인스턴스
}
}
let myPhoto: Photo = Photo()
myPhoto.enlarge()
print(PhotoSize.size)
myPhoto.reset()
print(PhotoSize.size)
위의 Photo
클래스의 reset
메서드에서 사용한 self
는 인스턴스 메서드 내부에서 사용한 self
로 Photo
클래스로 생성된 인스턴스 자체를 가리키고, PhotoSize
구조체의 zoomIn
메서드에서 사용한 self
는 타입 메서드에서 사용한 self
로 타입 메서드가 속한 PhotoSize
구조체 타입 자체을 가리킨다.
타입 메서드
내부에서 self
가 사용되었을때, 이때 self 는 타입 그 자체를 나타낸다.스위프트에는 메서드 이름을 callAsFunction
이라고 선언하면 인스턴스를 함수처럼 호출 할 수 있다.
struct Person {
var name: String = "이철수"
func callAsFunction() {
print("저의 이름은 \(name)입니다. 반갑습니다!")
}
func callAsFunction(age: Int) {
print("저의 나이는 \(age)입니다.")
}
func callAsFunction(height: Int) {
print("저의 키는 \(height)입니다.")
}
mutating func callAsFunction(name: String) {
self.name = name
}
}
var introduce: Person = Person()
introduce.callAsFunction()
introduce() //위의 표현과 동일한 표현
introduce.callAsFunction(age: 99)
introduce(age: 99) //위의 표현과 동일한 표현
introduce.callAsFunction(height: 180)
introduce(height: 180)
위의 코드와 같이 메서드 이름을 callAsFunction
으로 선언하면 introduce.callAsFunction()
와 introduce()
는 완전히 동일한 기능을 한다.