메서드는 특정 타입과 연관된 함수이다. 클래스,구조체,열거형은 모두 인스턴스 메서드를 정의할 수 있고 이러한 메서드는 주어진 타입의 인스턴스는 주어진 인스턴스를 사용하기 위해 특수한 기능을 하도록 캡슐화한다.
클래스나 구조체,열거형은 메서드를 정의 할 수 있다.
c와 object-c에서는 클래스에서만 메서드를 정의할 수 있지만, swift는 클래스,구조체,열거형에서 모두 정의할 수 있다.
인스턴스 메서드는 특정 클래스,구조체,열거형에 속하는 함수이다. 이러한 메서드는 인스턴스의 프로퍼티에 접근하고 수정하는 방법과 어떠한 목적과 관련된 기능을 제공하여 인스턴스 기능을 제공한다.
정의하는 방법은 일반 함수를 정의할 때와 동일한 방법으로 정의할 수 있다.
인스턴스 메서드는 인스턴스 내의 메서드나 프로퍼티에 접근할 수 있다.
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
위 클래스에서 increment,increment(by amount: Int),reset() 세가지 메서드가 정의되어 있다.
let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1
counter.increment(by: 5)
// the counter's value is now 6
counter.reset()
// the counter's value is now 0
동일한 이름의 메서드가 정의되었지만 parameter을 통해 구분할 수 있다.
모든 인스턴스는 self라는 암시적 속성이 있고 인스턴스 자기 자신을 뜻한다. self 프로퍼티를 사용하여 자기 자신의 메서드나 프로퍼티에 접근할 수 있다.
func increment() {
self.count += 1
}
굳이 self를 자주 사용할 필요는 없다. self를 붙이지 않으면 swift는 메서드 내의 프로퍼티나 메서드 이름을 참조한다. 만약 메서드의 parameter와 프로퍼티의 이름이 같은 경우는 반드시 self를 사용해야 한다.
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.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")
}
// Prints "This point is to the right of the line where x == 1.0
위 처럼 parameter:x와 프로퍼티 x를 구분하기 위해 반드시 self를 사용해야 한다.
그렇지 안흥면 모두 parameter로 처리를 한다.
구조체나 열거형의 Value 타입이다. 기본적으로 value type 프로펕티들은 인스턴스 메서드 내에서 수정할 수 없다. 하지만 수정을 하길 원한다면 mutating을 메서드 앞에 사용하여 수정할 수 있다.
메서드가 종료되면 메서드 내에 변화된 값들이 기존의 값으로 다시 초기화된다.메서드가 종료된 후에 새로운 프로퍼티값들이 할당되길 원한다면 self를 사용하면 된다.
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))")
// Prints "The point is now at (3.0, 4.0)
이렇게 프로퍼티를 수정하기 위해선 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)
}
}
위의 코드는 이전에 정의한 Count구조체에서 self를사용하여 아예 새로운 구조체를 할당하는 것이다.
열거형에서의 Mutating 메서드와 self는 아래와 같이 사용할 수 있다.
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를 추가하고 안하고의 상황에서 어떠한 차이가 있는지는 잘 모르겠다.
위의 메서드는 각자의 인스턴스 내에서 호출가능한 메서드였지만 타입 메서드를 호출하기 위해선 static 키워드드를 메서드 func키워드 앞에 적으면서 가능해진다.
클래스에서는 class키워드로 이를 대체하여 이를 상속받은 부모클래스의 메서드를 override하여 재정의 할 수 있다.
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
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 {
return level <= highestUnlockedLevel
}
@discardableResult
mutating func advance(to level: Int) -> Bool {
if LevelTracker.isUnlocked(level) {
currentLevel = level
return true
} else {
return false
}
}
}
LevelTracker 구조체에서 unlock,isUnlocked 메서드가 타입 메서드로 정의되어 있고 hightestUnlockedLevel은 타입 프로퍼티로 정의되어 있다.
advance 메서드는 inunlock의 반환값에 의해 curremtLevel을 수정하는 메서드이며, 구조체에서 프로퍼티의 속성값을 바꾸기 위해 mutating이 쓰여졌다.
@discardableResult속성은 함수가 값을 반환하자마자 반환값을 사용하지 않을 것이라고 알려주는 속성이다.
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
}
}
이젠 Player라는 클래스를 선언하고 직전에 선언한 LevelTracker 구조체 프로퍼티를 만들었다. Player의 Complete(level:)이 호출될때마다 LevelTracker의 타입 메서그 호출된다.
var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// Prints "highest unlocked level is now 2
위드 코드처럼 Player 클래스의 인스턴스를 만들고 인스턴스 메서드를 호출하게 되면 LevelTracker타입의 메서드를 호출하게 되고 타입 메서드가 변화시키는 값인 hightestUnlockedLevel이었으므로 모든 인스턴스에 영향을 끼친다.
player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
print("player is now on level 6")
} else {
print("level 6 hasn't yet been unlocked")
}
// Prints "level 6 hasn't yet been unlocked
위의 코드에서 advance(to:6)이 호출되었을 때 타입 프로퍼티 highestUnlockedLevel이 2이므로 isUnlocked가 False를 반환하므로 advance 또한 False를 반환하여서 그 결과가 위처럼 나타난다.