함수로 전달한 클로져는 자체 매개변수도 받아들일 수 있다.
“매개변수를 받지 않고 아무것도 반환하지 않는다” 를 의미하는 ( ) -> Void 를 사용해왔지만
func travel (action : (String) -> Void) {
print(“I’m getting ready to go.”)
action(“London”)
print(“I arrived!”)
}
Travel { (place: String) in
Print(“I’m going to \(place) in my car”)
}
우리는 “매개변수를 받지 않고 어느 것도 반환하지 않음” 이라는 의미로 ( ) -> Void를 사용해왔지만
Void를 클로져가 반환하기를 원하는 값의 자료 타입으로 교체할 수 있다.
이를 보여주기 위해, 우리는 클로져를 유일한 매개변수로 받아들이는 함수
func travel(action: (String) -> String) {
print(“I’m getting ready to go.”)
let description = action(“London”)
print(“I arrived!”)
}
travel { (place:String) -> String in
return “I’m going to \(place) in my car”
}
위에서 만든 travel() 함수는 한 개의 매개변수를 받아들이는데
이것은 하나의 매개변수를 받아들이고 문자열을 반환하는 클로져이다.
func travel(action: (String) -> String) {
print(“I’m getting ready to go.”)
let description = action(“London”)
print(“description)
print(“I arrived!”)
}
travel { (place: String) -> String in
return “I’m going to \(place) in my car”
}
travel { place -> String in
return “I’m going to \(place) in my car”
}
travel { place in
return “I’m going to \(place) in my car”
}
travel { place in
“I’m going to \(place) in my car”
}
스위프트는 더 짧게 작성할 수 있는 단축 구문을 갖고 있다.
travel {
“I’m going to \($0) in my car”
}
두 가지 매개변수를 사용하는 다른 클로져 예제를 적어볼 것이다.
travel() 함수는 이제 여행하는 장소와 가는 속도를 지정하는 클로져를 필요로한다.
func travel(action: (String, Int) -> String ) {
print(“I’m getting ready to go.”)
let description = action(“London”, 60)
print(description)
print(“I arrived!”)
}
travel {
“I’m goingt to \($0) at \($1) miles per hour.”
}
함수에 클로져를 전달한 것과 같은 방식으로 클로져를 함수로부터 반환받을 수도 있다.
이 구문은 ‘->’ 를 두 번 사용하기 때문에 조금 혼란스러울 수 있다.
함수의 반환 값을 특정하기 위해 한 번,
클로져의 반환 값을 특정하기 위해 한 번 사용된다.
func travel() -> (String) -> Void {
return {
print(“I’m going to \($0)”)
}
}
let result = travel()
result(“London”)
let result2 = travel()(“London”)
클로져 안에서 외부 값을 사용할 때 Swift는 이것을 캡쳐한다 – 클로져와 함께 저장하므로 더 이상 존재하지 않더라도 수정될 수 있다.
func travel() -> (String) -> Void {
return {
print(“I’m going to \($0)”)
}
}
let result = travel()
result(“London”)
func travel() -> (String) -> Void {
var counter = 1
return {
print(“\(counter). I’m going to \($0)”)
counter += 1
}
}
Counter 변수가 travel()안에서 만들어졌더라도 이것은 클로져에 의해 캡쳐되기 때문에 그 클로져에서 계속 살아있다.
result(“London”)
result(“London”)
result(“London”)
Swift closure의 가장 중요한 특징 중 하나는 사용하는 값을 캡쳐한다는 것이다.
동시에, Siwft의 가장 혼란스러운 특징 중 하나는 그들이 사용하는 값을 캡쳐한다는 것이다.
값을 캡쳐함으로써 closure가 필요할 때마다 그 데이터에 항상 접근할 수 있다는 것은 swift가 그 클로져를 안전하게 실행할 수 있다는 것을 의미한다.
랜덤 숫자를 발생시키는 함수를 작성해보자 : 한 줄에 같은 숫자를 두 번 반환하지는 않는다.
이 논리는 다음과 같다
루프가 한번 끝나면 이는 숫자가 이전 숫자와 다르다는 것을 의미하고
previousNumber를 newNumber로 업데이트하고 반환한다.
이것은 클로져로 반환되기 때문에 우리는 어디에서나 랜덤 숫자를 발생시킬 수 있다.
func makeRandomNumberGenerator() -> () -> Int {
return {
var previousNumber = 0
var newNumber : Int
repeat {
newNumber = Int.random(in : 1…3)
} while newNumber == previousNumber
previousNumber = newNumber
return newNumber
}
}
let generator = makeRandomNumberGenerator()
for _ in 1…10 {
print(generator())
]
실행해보면 계획대로 진행되지 않는다 – 나는 여러 번 반복되는 숫자를 받았다, e.g. 1,2,1,1,3,1,3,3,3,2. 와 같이
나는 반복되지 않는 숫자를 원했다. 문제는 다음과 같다.
return {
var previousNumber = 0
var newNumber : Int
}
var previousNumber = 0
return {
var newNumber : Int
}
이 코드에서는 원하는대로 실행되는 것을 볼 수 있다 – 반복되지 않는 매번 새로운 랜덤 값을 받는다.
여기서 클로져 캡쳐의 힘을 알 수 있다.
previousNumber 변수가 클로져 안에 있지 않지만
클로져가 실행되기 위해 그 변수가 존재해야하기 때문에 이것은 캡쳐된다.
즉, Swift는 makeRandomNumberGenerator() 의 실행이 완료되고 일반적으로 파괴된 이후에도 그 변수가 존재를 유지하도록 한다.
이것은 두 가지 이유에서 중요하다.