1. 개요
스위프트에서 매세드는 특정 타입에 관련된 함수를 뜻함.
클래스, 구조체, 열거형에서 관련된 기능을 제공 하는 "인스턴스 메서드" 정의 가능
타입만으로 접근 가능한 "타입 메서드" 정의 가능
구조체와 열거형이 메서드를 가질 수 있다는 것은 기존 언어와의 다른점
2. 인스턴스 메서드(Instance Methods)
특정 타입의 인스턴스에 속한 함수( 타입(클래스,구조체,열거형) 내부에 구현 )
인스턴스 내부의 프로퍼티 값을 변경하거나 특정 연산 결과를 반환하는 등
인스턴스와 관련된 기능을 실행( 즉, 인스턴스가 존재할때만 수행 가능 )
class Counter {
var count = 0
func increment() {
count += 1 //self.count += 1 이라는 표현과 같음.
// 이것이 가능한 이유는 Swift에서 특정 메소드에서
// 해당 인스턴스에 등록된 메소드나 프로퍼티를 호출하면
// 현재 인스턴스의 메소드나 프로퍼티를 사용하는 것으로
// 자동으로 가정하기 때문입니다
// 만약 매개변수가 있고 그 매개변수 이름이
// 프로퍼티 이름과 같은 경우에는
// self로 프로퍼티랑 매개변수랑 구분을 확실히 해줘야한다.
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
let counter = Counter()
// 초기 count 값은 0입니다.
counter.increment()
// count 값이 1로 변경 됐습니다.
counter.increment(by: 5)
// count 값은 현재 6입니다.
counter.reset()
// count 값은 0이 됩니다.
self 프로퍼티
모든 프로퍼티는 암시적으로 인스턴스 자체를 의미하는 self라는 프로퍼티를 갖습니다. 인스턴스 메소드 안에서 self프로퍼티를 이용해 인스턴스 자체를 참조하는데 사용할 수 있습니다.
//위의 Counter클래스의 인스턴스 매서드 increment를 아래처럼 표현 가능
func increment() {
self.count += 1
}
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
// 매개변수 이름과 프로퍼티의 이름이 동일할시 self로 구분
// self.x를 이용해 프로퍼티 x와 인자 x를 구분
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
print("This point is to the right of the line where x == 1.0")
}
// "This point is to the right of the line where x == 1.0" 출력
구조체와 열거형(값 타입)의 "인스턴스 메서드"에서 프로퍼티 변경
키워드 mutating ( 얘는 프로퍼티를 변경하는 함수다~ )
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// "The point is now at (3.0, 4.0)" 출력
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// let으로 선언해서 값 변경 시도시 에러 발생!
// mutating 선언과 상관없이 메소드로 값을 변경할 수 없습니다
구조체 열거형의 Mutating 메소드 내에서 self 할당
Mutating메소드에서 self프로퍼티를 이용해 완전 새로운 인스턴스를 생성할 수 있습니다.
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)
}
}
열거형에서 Mutating메소드를 사용해 다른 상태를 표현할 수 있습니다.
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 값은 .high
ovenLight.next()
// ovenLight 값은 .off
3. 타입 메서드(Type Methods)
특정 타입 자체에서 호출해 사용합니다.
func앞에 static혹은 class키워드를 추가
타입 변수와 마찬가지로 static메소드와 class메소드의 차이점은
static메소드는 서브클래스에서 오버라이드 할 수 없는 타입 메소드 이고,
class메소드는 서브클래스에서 오버라이드 할 수 있는 타임 메소드 라는 것.
Swift에서는 클래스, 구조체, 열거형에서 모두 타입 메소드를 사용할 수 있습니다
타입 메소드도 인스턴스 메소드와 같이 점(.) 문법으로 호출할 수 있습니다.
하지만 인스턴스에서 호출하는 것이 아니라 타입 이름에서 메소드를 호출
class SomeClass {
class func someTypeMethod() {
// 타입 메소드 구현
}
}
SomeClass.someTypeMethod() // 타입 메소드 호출!
타입 메소드 안에서도 self키워드를 사용할 수 있습니다.
예제) 게임 레벨(단계) 추적
타입 메소드에서의 self는 인스턴가 아니라 타입 자신을 의미합니다.또 타입 메소드 안에서 다른 타입 메소드를 사용하는 것이 가능합니다. 코드를 보시겠습니다.
struct LevelTracker {
static var highestUnlockedLevel = 1 // 지금까지의 최고 레벨 타입 저장변수
var currentLevel = 1 //현재 레벨 인스턴스 저장변수
static func unlock(_ level: Int) { //다음레벨 열기 타입 메서드
if level > highestUnlockedLevel { highestUnlockedLevel = level }
}
static func isUnlocked(_ level: Int) -> Bool {
//레벨이 지금까지의 최고레벨 이하이면 true
//즉, 이 레벨은 지금 unlock된 최고 레벨 이하이니 이 레벨은 해제되어있다.
return level <= highestUnlockedLevel
}
@discardableResult // 반환값 사용 안해도 되니 경고 표시 하지말아요~
mutating func advance(to level: Int) -> Bool { // 다음 레벨로 넘어가기 인스터스메서드
if LevelTracker.isUnlocked(level) {
// 그 다음레벨이 해제 되어있냐?
//해제 되었으면 그 레벨이 현재 레벨로 지정.
currentLevel = level
return true
} else {
// 해제 안되있으면 false 이 레벨은 해제가 안되어있으니 못들어간다.
return false
}
}
}
Player클래스의 complete메소드에서 LevelTracker 인스턴스 tracker와 타입메소드 LevelTracker.unlock를 사용해 특정 사용자의 현재 레벨을 추적하도록 구현
class Player {
var tracker = LevelTracker()
let playerName: String
func complete(level: Int) {
LevelTracker.unlock(level + 1)
tracker.advance(to: level + 1)
}
init(name: String) {
playerName = name
}
}
// 레벨 1을 완료해서 레벨 2가 열렸습니다.
var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// "highest unlocked level is now 2" 출력
// 다른 플레이어가 레벨 6에 접근 -> 아직 열리지 않음.
player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
print("player is now on level 6")
} else {
print("level 6 has not yet been unlocked")
}
// "level 6 has not yet been unlocked" 출력