메서드는 특정 타입과 연관된 함수이다. 클래스, 구조체, 열거형은 주어진 타입의 인스턴스 동작을 위한 특정작업과 기능을 지원하는 메서드를 정의할 수 있다. 그리고 이들은 또한 타입 자체와 연관된 타입 메서드 정의도 가능하다.
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount : Int) {
count =+ amount
}
func reset() {
count = 0
}
}
// Counter클래스는 3개의 인스턴스 메서드를 정의한다.
//각 인스턴스 메서드는 호출에 따라서 count프로퍼티에 대한 기능을 적용한다.
let counter = Counter()
//인스턴스 생성
counter.increment()
//count = 1
counter.increment(by: 5)
//count = 6
counter.reset()
//count = 0
func increment() {
self.count += 1
}
//다음과 같이 위의 increment메서드는 작성이 가능하다.
//실제 코드에서는 self를 작성할 필요가 없다. self를 명시적으로 작성하지 않으면,
//Swift는 메서드 내에서 이미 알고있는 프로퍼티나 메서드를 사용할때마다
//현재 인스턴스의 프로퍼티나 메서드를 참조한다고 가정하기 때문이다.
//하지만 인스턴스 메서드에 파라미터 명이 인스턴스 프로퍼티와 동일할 때 명시해야 한다.
struct point {
var x = 0.0, y = 0.0
func isToTheRightOf(x : Double) -> Bool {
return self.x > x
}
}
//리턴하는 값에서 파라미터는 그냥 x이며, 인스턴스의 프로퍼티는 self.x를 통해서 분별하였다.
struct Point {
var x = 0.0
var 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 구조체 값을 설정한다.
somePoint.moveBy(x: 2.0, y : 3.0)
print(somePoint.x, somePoint.y)
//3.0, 4.0을 출력하게 된다.
//구조체는 값 타입으로 이를 외부 메소드로 변경할 수 없으나,
//내부에서 메서드 값 수정을 위한 함수를 설정하여 조정이 가능하다.
//그리고 이를 변수값으로 사전에 정의한 것도 포인트.
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 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()
//다음과 같은 경우 .high로 변경된다.
ovenLight.next()
//다음인 .off로 변경된다.
자체 인스턴스에 대한 값을 self를 통해서 반영해준다.
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 {
return level <= highestUnlockedLevel
}
@discardableResult
mutating func advance(to level : Int) -> Bool {
if LevelTracker.isUnlocked(level) {
currentLevel = level
return true
} else {
return false
}
}
}
//LevelTracker구조체는 모든 플레이어가 푼 가장 높은 레벨을 추적한다.
//이 값은 highestUnlockedLevel이라는 프로퍼티에 저장된다.
//이와 더불어 위 프로퍼티와 동작하는 2개의 타입 메서드도 정의한다.
//이 타입 메서드는 LevelTracker.highestUnlockedLevel로 작성하지 않아도,
//해당 프로퍼티에 접근이 가능하다.(타입 자체의 타입 변수이므로, 호출하지 않아도..?)
//이 외에도 각 플레이어의 진행사항을 추적한다.
//플레이어가 현재 플레이 중인 레벨을 추적하는 currentLevel이라는 인스턴스 프로퍼티를 사용한다.
//이 currentLevel 프로퍼티 관리를 돕기 위해서 별도의 인스턴스 메서드를 정의한다.
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
}
}
let player = Player(name: "경윤")
var tracker = LevelTracker()
tracker.currentLevel = 12
print(tracker.currentLevel)
//다음과 같이 인스턴스 생성 후 타입 변수와 메서드에 접근하려 하는 경우 에러가 발생한다.
LevelTracker.highestUnlockedLevel = 3
print(LevelTracker.highestUnlockedLevel)
//다음과 같이 인스턴스를 생성하지 않고 바로 접근할 경우 타입 변수에 접근이 가능하다.
//인스턴스를 생성한 후 해당 값으로 접근이 안되지만, 타입에 고유하게 할당되어 조작이 가능하다.