파라미터는 함수 본문 안에 있는 지역 변수이다. 기본적으로 let
으로 선언되기 때문에 함수 안에서 다른 값을 할당할 수 없다.
대신 함수 안에서 var
키워드로 파라미터 이름과 같은 변수를 선언할 수 있다. 이렇게 선언한 변수의 값을 바꾸는 것은 파라미터의 복사본의 값을 바꾸는 것과 같다. 원래 파라미터가 가지는 값은 변하지 않는다.
인자로 전달된 원래 변수의 값을 바꾸려면 다음과 같은 조건이 필요하다.
inout
이라는 키워드를 붙인다.var
로 선언되어야 한다.&
키워드를 이용해 주소를 전달할 수 있다.// inout 키워드 사용 예시
func removeCharacter(_ c: Character, from s: inout String) -> Int {
var howMany = 0
while let ix = s.firstIndex(of:c) {
s.remove(at:ix)
howMany += 1
}
return howMany
}
var s = "hello"
let result = removeCharacter("1", from: &s)
// s == "heo"
// result == 2
Cocoa API는 C와 Objective-C로 작성되었기 때문에 Modifiable parameter를 쓸 때 inout
대신 UnsafeMutablePointer
라는 키워드를 사용한다.
그러나 함수를 호출하는 입장에서는 스위프트에서와 동일하게 var
변수의 주소를 전달하기만 하면 된다.
가끔 Cocoa가 우리가 작성한 함수를 UnsafeMutablePointer
와 함께 호출하고, 그 값을 변경하고 싶을 때가 있다. 이때 우리는 스위프트가 아닌 Objective-C에게 말을 거는 것이기 때문에 inout
이 아닌 UnsafeMutablePointer
를 사용해야 한다.
// pointee 프로퍼티 사용에 주목
func popoverPresentationController(_ popoverPresentationController: UIPopoverPresentationController, willRepositionPopoverTo rect: UnsafeMutablePointer<CGRect>, in view: AutoreleasingUnsafeMutablePointer<UIView>) {
view.pointee = self.button2
rect.pointee = self.button2.bounds
}
(이 부분은 아직 Objective-C를 몰라서 이해가 잘 가지 않는다. 나중에 공부하고 다시 보는 걸로..)
파라미터로 class
의 인스턴스가 올 경우에만 inout
을 사용하지 않고 파라미터의 값을 바꿀 수 있다. 인스턴스 멤버의 값을 바꿔도 파라미터로 온 인스턴스 자체는 변하지 않는다. 클래스 인스턴스는 mutuable(변경 가능)하다는 특징을 가진다.
정확하게 말하면 클래스는 reference type이고 다른 오브젝트 타입들은 value type이다. 따라서 struct의 인스턴스를 인자로 전달하면 인스턴스의 복사본이 전달된다. 반면 클래스의 인스턴스는 클래스 인스턴스의 레퍼런스가 전달된다.
함수는 어디서든 선언될 수 있다. 심지어 함수의 본문 안에서도 선언될 수 있다.
함수의 본문 안에서 선언된 함수(local function)은 선언된 후 같은 스코프 내에서 호출될 수 있다. 하지만 다른 곳에서는 보이지 않는다.
이는 함수의 정교한 구조를 설계할 때 유용하다. 예를 들어 함수 A만 함수 B를 호출한다면 함수 A 안에 함수 B를 포함할 수 있다.
함수는 자기 자신을 호출할 수 있다. 이를 재귀(recursion)이라고 한다.
스위프트에서 함수는 일급 시민(first-class citizen)이다. 이는 함수가 값(value)이 사용되는 어느 곳에서든 사용될 수 있다는 것을 의미한다.
스위프트는 타입을 엄격하게 구분하기 때문에 함수를 값으로 사용하는 경우에는 함수가 반드시 타입을 가져야 한다. 이때 함수의 타입은 함수의 시그니처
이다.
함수를 값으로 사용하는 주된 목적은 이 함수가 무엇인지 정확히 알지 않아도 나중에 함수를 값으로 사용할 수 있도록 하는 것이다.
// function f's signature: () -> ()
func doThis(_ f:() -> ()) {
f()
}
// declare a function of the proper type(() -> ())
func whatToDo() {
print("I did it")
}
// pass as argument a function reference
doThis(whatToDo)
Cocoa API에서는 런타임 또는 나중에 호출될 함수를 전달하는 상황이 많다. 심지어 두 개의 함수를 인자로 전달하는 경우도 많다.(ex. UIView.animate(withDuration:animations:completion)
)
Cocoa 문서는 주로 전달되는 함수를 handler
라고 표현하고 이를 block
으로 참조한다. 이는 Objective-C 구문이다.
스위프트의 typealias
를 이용하면 함수 타입에 이름을 지정해줄 수 있다. 이를 사용하면 함수 타입을 더욱 명확하게 표현할 수 있다.