closure
파트2입니다,
클로저는 스위프트에서 중요한 문법이니까 시간될 때 클로저만 따로
정리해서 글 올려보겠슴다
참고로 여기부턴 제목이 겁나 깁니다
이제 closure
가 약간 복잡하게 느껴질텐데요
함수에 인자로 넘겨준 closure
는 자기만의 인자도 받을 수 있답니다?
우리는 여태 () -> Void
문구를 사용했죠. 인자를 받지않고 반환값도 없다는 뜻으로요. 하지만 이제 ()
에 closure
받을 인자의 타입을 작성할 수 있슴다
그럼 코드로 확인해 봐야겠죠? 앞서 작성했던 travel()
함수에서 유일하게 인자로 받은 closure
가 String
을 받는다고 해보죠
func travel(action: (String) -> Void) {
print("I'm getting ready to go.")
action("London")
print("I arrived!")
}
이제 travel()
함수를 trailing closure 문법으로 호출하려면 closure
에 string
인자가 필요합니다
travel { (place: String) in
print("I'm going to \(place) im my car")
}
만약 앞선 용법처럼 String
을 생략하면 어찌될까요?
인자가 1개 필요하고 그것은 무시될 수 없다고 에러가 뜹니다
방금 앞의 파트는 인자로 사용한 클로저가 인자를 받는 경우였습니다.
경찰청 철창살은 외철창살이냐 쌍철창살이냐
이번에는 값을 반환하는 경우에 대해 알아볼게요
앞에서는 () -> Void
에 빈 괄호를 채웠습니다.
이번에는 Void
가 써있는 자리를 데이터의 타입으로 바꿔서
클로저가 값을 반환하도록 해보죠
아까와 같은 travel()
함수에 String
반환만 추가해주겠습니다
func travel(action: (String) -> String {
print("I'm getting ready to go.")
let description = action("London")
print(description)
print("I arrived!")
}
이번엔 action
을 바로 출력하지 않고 description
이라는
상수에 할당해서 출렸했네요
그리고 trailing closure를 사용할 때도 마찬가지로 반환하는 데이터 타입을 꼭 작성해줘야합니다.
반환값이 있으니까 return
도 추가해줘야겠죠?
travel { (place: String) -> String in
return "I'm going to \(place) in my car"
}
우리가 방금 만든 travel()
함수는 인자를 closure
한개만 받죠
그리고 closure
자체도 하나의 인자를 받고 string
값을 반환합니다.
두 개의 print()
사이에서 작동하구요
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"
}
그런데 말입니다.
Swift는 closure
의 인자가 반드시 String
이 될것을 압니다.
따라서 그냥 생략해도 됩니다. 으잉?
travel { place -> String in
return "I'm going to \(place) in my car"
}
그리고 반환값이 String
인 것도 알고 있어서 생략해도 됩니다.
travel { place in
return "I'm going to \(place) in my car"
}
그리고 한 가지 반환값을 가지는 한줄의 코드만 가지고 있으면
return
도 생략해도 됩니다. 뭔 일이냐 이게
travel { place in
"I'm going to \(place) in my car"
}
끝일거 같죠? 더 생략할 부분이 남아있습니다.
place in
을 생략하고 Swift가 클로저 인자에
자동적으로 이름을 제공하게 할 수 있어요
$
기호를 사용하고 0
부터 자동 카운팅 됩니다
travel {
"I'm going to \($0) in my car"
}
이건 오랜만에 봐도 뭔가 허무한 느낌이네요
이부분도 다음에 다시 다루어 보겠습니다
인자를 여러개 받는 클로저에 대해 알아보죠
이번travel()
함수는 누가 '어디로'가는지에 대한 것과 얼마나 빠른 '속도'로 가는지에 대한 클로저를 인자로 받을 거에요
그말인 즉슨 String
과 Int
를 받겠다는거죠
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 going to \($0) at \($1) miles per hour."
}
인자를 2개 받는것 뿐이라 간단하네요
$0
기호로 쓰는것이 헷갈리는 분들은 원래대로 \(place)
쓰셔도 무방합니다
함수에 클로저를 넘겨주듯이 함수에서 클로저를 반환받을 수도 있어요
이 방법이 처음에 좀 헷갈리는데 ->
를 두번 사용합니다
첫 번째는 함수의 반환값을 특정하고, 두 번째는 클로저의 반환값을 특정합니다.
이제는 단골이죠? travel()
함수를 다시 만들어 보겠습니다
이번엔 인자를 안 받고 클로저를 반환하게 작성해보죠
func travel() -> (String) -> Void {
return {
print("I'm going to \($0)")
}
}
->
를 두번 사용한게 보이시죠?
그리고 호출할 떄는 아래처럼 합니다
let result = travel()
result("London")
그리고 권장하지는 않지만 아래 방법으로도 가능합니다
let result2 = travel()("London")
만약 외부의 값을 클로저 내부에 사용한다면 Swift가 capture
해둡니다
클로저랑 같이 보관을 해두기 때문에 더이상 존재하지 않더라도 수정이 가능하답니다?
예시를 보자...
클로저를 반환하는 travel()
함수가 있죠
반환되는 클로저는 String
을 유일한 인자로 받고 따로 반환값은 없어요
func travel() -> (String) -> Void {
return {
print("I'm going to \($0)")
}
}
그리고 클로저를 받고 호출 가능하구요
let result = travel()
result("London")
이거 아까 했던거 아니냐구요?
언제 caputre
하냐구요?
이제 합니다!
travel()
함수안에 클로저에서 사용되는 값을 생성할 경우에 일어납니다
클로저가 몇번 호출되었는지 확인하는걸 예로 들어보죠
func travel() -> (String) -> Void {
var counter = 1
return {
print("\(counter). I'm going to \($0)")
counter += 1
}
}
counter
변수는 travel()
내부에서 생성되었으니 함수내부에서만 유효하다고 생각되지만 클로저랑 같이 capture
되서 계속 유효함을 유지합니다
그래서 result("London")
을 여러번 호출하면 counter
변수는 증가합니다
result("London")
result("London")
result("London")
$0
,$1
같은 약식 표현을 제공합니다. 근데 사용이 필수는 아니에요capture
되서 나중에 클로저가 값에 영향을 줄 수 있습니다.휴 클로저 파트가 끝났네요.
저자도 중요한 부분이라 생각했는지 2파트에 걸쳐서 했습니다
처음 시작부에서도 말했듯이 클로저는 중요한 문법이니까 후에
클로저만 정리해서 한번 더 포스팅 할게요