Swift Language
Swift Language - 10 - 메소드 (Methods)
xnoag
2023. 2. 1. 09:30
인스턴스 메소드 (Instance Methods)
class Counter {
var count = 0
func increment() {
count += 1
}
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 프로퍼티 (The self Property)
// 모든 프로퍼티는 암시적으로 인스턴스 자체를 의미하는 self라는 프로퍼티를 갖습니다.
// 인스턴스 메소드 안에서 self프로퍼티를 이용해 인스턴스 자체를 참조하는데 사용할 수 있습니다.
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
func increment() {
self.count += 1
}
/* 앞의 예제에서는 increment()메소드에서는 count += 1이라 표현했지만
사실은 self.count += 1의 의미 입니다.
이것이 가능한 이유는 Swift에서 특정 메소드에서 해당 인스턴스에 등록된 메소드나 프로퍼티를 호출하면
현재 인스턴스의 메소드나 프로퍼티를 사용하는 것으로 자동으로 가정하기 때문입니다.
위 규칙이 적용되지 않는 예외적인 상황이 있습니다. 바로 인자 이름이 프로퍼티 이름과 같은 경우 입니다.
이 경우에는 프로퍼티에 접근하기 위해 명시적으로 self키워드를 사용해야 합니다.
다음은 self키워드를 이용해 파라미터와 프로퍼티의 모호함을 명확하게 한 (예)입니다. */
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x // self.x를 이용해 프로퍼티 x와 인자 x를 구분, Point의 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" 출력
인스턴스 메소드 내에서 값 타입 변경 (Modifying Value Types from Within Instance Methods)
/* 값 타입 형의 메소드에서 프로퍼티를 변경하고 싶을 때가 있을 텐데요. 어떻게 해야할까요?
바로 메소드에 mutating붙여 주면 가능합니다.
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)" 출력
Mutating 메소드 내에서 self 할당 (Assigning to self Within a Mutating Method)
// 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
타입 메소드 (Type Methods)
// 타입 메소드의 선언은 메소드 키워드 func앞에 static혹은 class키워드를 추가하면 됩니다.
// static메소드와 class메소드의 차이점은 static메소드는 서브클래스에서 오버라이드 할 수 없는 타입 메소드 이고, class메소드는 서브클래스에서 오버라이드 할 수 있는 타입 메소드 라는 것입니다.
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
}
}
}
/* advance메소드 앞에 붙은 @discardableResult키워드는
리턴 값이 있는 메소드에서 리턴 값을 사용하지 않으면 컴파일러 경고가 발생하는데,
그 경고를 발생하지 않도록 해줍니다. */