과제 구현을 하면서 클로저라는 친구를 이해하기 위해 노력함
다른 분들도 다들 어려움을 겪고 있는 거 같아서 제대로 한 번 짚고 넘어가야 할 듯 했음!
일단 오늘은 두 개의 Int 값을 받아 문자열을 반환하는 클로저를 설계하고,
해당 클로저를 상수에 저장해서 사용하는 법을 익혔음
클로저를 함수의 파라미터로 전달하고,
함수 내부에서 해당 클로저를 호출하는 방식도 연습했음
클로저를 써본 기억이... 없어서... 0부터 출발하려니 막막..
일단 Lv 1까지 구현해봄
// Int 두 개 받아서 문자열을 반환하는 클로저를 정의하고 sum 상수에 저장
let sum: (Int, Int) -> String = { a, b in
let result = a + b // 두 숫자를 더해서 result에 저장
return "두 수의 합은 \(result) 입니다" // 문자열로 포맷팅
}
var num: Int = 3 // num을 3으로 초기화
let message = sum(num, 7) // sum 클로저 호출, 결과 문자열을 message에 저장
print(message)
// 클로저를 파라미터로 받아서 호출하는 함수 정의
func calculator(closure: (Int, Int) -> String) {
let result = closure(4, 5) // 전달받은 클로저를 4랑 5로 호출 (4 + 5)
print(result)
}
calculator(closure: sum) // sum 클로저를 calculator 함수에 전달 실행
클로저는 그 자체로 함수처럼 사용할 수 있는 값이라는 점이 인상 깊었음
솔직히 처음에는 굳이 써야하나.. 싶었는데
클로저를 다른 함수에 인자로 전달하고 내부에서 호출하는 것이 생각보다 직관적임을 깨달음
처음엔 calculate처럼만
calculator(sum)
요로코롬..! 써도 되는 줄 알았는데,
Swift가 라벨을 명시하는 걸 기본으로 해서 그런지
closure:라는 파라미터 이름을 붙여야 한다는 것도 알게 되었음
calculator(closure: sum)
이름 없는 함수
함수처럼 어떤 일을 하는 코드 묶음?인데 이름이 없음
주로 변수에 저장해서 쓰거나 다른 함수에 넘겨줘서 사용함
func after1Second(task: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: task)
}
after1Second {
print("1초 뒤에 실행됨!")
}
@escaping으로 지금 print를 실행하는 게 아니라, 1초 뒤에 실행되게 전달한 거.
지금 말고 나중에 해줘 ~~~ .. 인 느낌.
코드를 값처럼 다룰 수 있어서, 나중에 실행하거나 전달하기 좋은 듯
func doSomethingBeforeWork(work: () -> Void) {
print("밥 먹기 전")
work()
}
doSomethingBeforeWork {
print("손 씻기")
}
이런 식으로 함수에 다른 동작을 전달할 수 있음
let numbers = [5, 2, 9]
let sorted = numbers.sorted(by: { $0 < $1 })
// OR 더 간단하게 가능
let sorted2 = numbers.sorted(by: <)
{ (파라미터) in
// 코드
return 결과
}
ex)
let sayHello = {
print("Hellooooo")
}
sayHello() // Hellooooo
let add: (Int, Int) -> Int = { a, b in
return a + b
}
print(add(3, 5)) // 8
👉 add는 클로저를 저장한 변수.
👉 (Int, Int) -> Int는 입력 두 개 받고 결과 하나(Int)를 리턴하는 것
func calculator(closure: (Int, Int) -> Int) {
print(closure(4, 5))
}
calculator(closure: add) // 9
클로저를 함수에 파라미터로 줄 수 있음
이때 closure: 라는 이름(label) 을 붙여야 함....!!!!!!!!!
let hello = {
return "안녕"
}()
print(hello) // 안녕
👉 이렇게 바로 실행하고 결과를 저장할 수도 있음
func delayPrint(closure: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
closure()
}
}
함수 안에서 클로저는 보통 함수가 끝나기 전에 실행돼야 하는데
이렇게 나중에에 실행하려면 @escaping을 붙여야 함
탈출해서 나중에도 살아있을 거임!!!!!!! <- 이런 느낌이랄까
클로저가 외부 변수를 기억하는 기능
var count = 0
let closure = {
print(count)
}
count = 5
closure() // 5
👉 클로저는 외부에 있는 변수도 기억해서 쓸 수 있음
| 개념 | 설명 |
|---|---|
| 클로저 | 이름 없는 함수 |
| 저장 | 변수에 저장해서 사용 가능 |
| 전달 | 함수의 파라미터로 전달 가능 |
| 즉시 실행 | 클로저 뒤에 () 붙이면 바로 실행됨 |
| @escaping | 함수 끝나고도 클로저를 실행하고 싶을 때 필요 |
| 클로저 캡처 | 클로저가 외부 변수 기억해서 사용하는 것 |
클로저는 익명 배달원? 이라고 생각할 수 있을 듯
보통 일상생활에서 배달을 받을 때 배달원이 누구인지는 중요하지 않음 그냥 배달만 받으면 배달원의 할 일 끝.
그것처럼 그냥 할 일을 정해주고, 시키면 그냥 하는 역할임
쉽게 풀면 지금 바로 시켜도 되고 나중에 (escaping) 시킬 수도 있는 것
밖에 있는 물건(count 같은 변수)을 들고 가서 기억하고 쓸 수도 있는 ??
함수랑 비슷하면서도 다르고, 눈에 보이지 않는 복잡한 동작이 숨어있어서
어렵다고 느껴지는 듯 함.. 클로저에 대해 좀 깊게 톺아보았던 것 같음 !!