Swift - 메소드

임성빈·2022년 3월 21일
0

Swift

목록 보기
11/26
post-thumbnail
post-custom-banner

메소드

특정 타입의 클래스, 구조체, 열거형과 관련된 함수를 메소드라 한다.
특정 타입의 인스턴스에서 실행할 수 있는 메소드를 '인스턴스 메소드', 특정 타입과 관련된 메소드를 '타입 메소드'라 한다.


인스턴스 메소드

인스턴스 메소드는 특정 클래스, 구조체, 열거형의 인스턴스에 속한 메소드이다. 이 메소드를 통해 인스턴스 내의 값을 제하거나 변경할 수 있다. 인스턴스 메소드는 이름 그대로 그 인스턴스가 속한 특정 타입의 인스턴스에서만 실행 가능하다.

class Counter {
	var count = 0
    func increment() {
    	count += 1
	}
    func increment(by amount: Int) {
    	count += amount
	}
    func reset() {
    	count = 0
	}
}

Counter 클래스를 선언하고 인스턴스 메소드로 각각 increment , increment(by amount: Int) , reset() 를 정의해 인스턴스 내의 count 프로퍼티를 변경하는 기능을 수행한다.

self 프로퍼티

모든 프로퍼티는 암시적으로 인스턴스 자체를 의미하는 self 라는 프로퍼티를 갖는다. 인스턴스 메소드 안에서 self 프로퍼티를 이용해 인스턴스 자체를 참조하는데 사용할 수 있다.

func increment() {
	self.count += 1
}

처음 예제와 위의 예제의 incerment() 메소드에서의 의미는 같다. 이것이 가능한 이유는 Swift에서 특정 메소드에서 해당 인스턴스에 등록된 메소그나 프로퍼티를 호출하면 현재 인스턴스의 메소드나 프로퍼티를 사용하는 것을 자동으로 가정하기 때문이다.
단, 인자 이름이 프로퍼티 이름과 같은 경우 위 규칙이 적용되지 않는 예외적인 상황이 된다. 이 경우 프로퍼티에 접근하기 위해 명시적으로 self 키워드를 사용해야 한다.

struct Point {
	var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
    	return self.x > x
        // self.x 를 이용해 프로퍼티 x와 인자 x를 구분
    }
}

let somePoint = Point(x: 4.0, y:5.0)

if somePoint.isToTheRightOf(x: 1) {
	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 키워드를 붙여주면 가능하다.
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)" 출력

Point 는 구조체여서 메소드로 인스턴스의 값을 변경할 수 없지만 mutating 키워드를 붙여 값을 변경할 수 있다. 그러기 위해서는 Point 인스턴스를 var somePoint 로 선언해야 가능하다.

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: Double, y: y + deltaY: Double)
 	}
}

타입 메소드

인스턴스 메소드는 특정 타입의 인스턴스에서 호출되고, 타입 메소드는 특정 타입 자체에서 호출해 사용한다. 타입 메소드의 선언은 메소드 키워드 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
        }
    }
}

위 코드는 타입 메소드 3개와 mutating 메소드 1개를 선언해 현재 레벨, 최고 레벨, 다음 레벨 열기, 다음 레벨 넘어가기 기능을 만 수행한다. 게임에서 최고 레벨이 어디인지 추적하고 만약 그 레벨이 열려 있으면 그쪽으로 다른 사용자가 바로 넘어갈 수 있는 advance 기능을 제공한다. @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 클래스의 complete 메소드에서 LevelTracker 인스턴스 tracker 와 타입메소드 LevelTracker.unlock 를 사용해 특정 사용자의 현재 레벨을 추적하도록 구현한다.

var player = Player(name: "John")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highsetUnlocked)")
// "highest unlocked level is now 2" 출력
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" 출력
profile
iOS 앱개발
post-custom-banner

0개의 댓글