Closure

hyun·2025년 6월 2일
2

iOS

목록 보기
9/54

 클로저, 함수 파라미터 전달

과제 구현을 하면서 클로저라는 친구를 이해하기 위해 노력함
다른 분들도 다들 어려움을 겪고 있는 거 같아서 제대로 한 번 짚고 넘어가야 할 듯 했음!

일단 오늘은 두 개의 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)

 클로저

이름 없는 함수

함수처럼 어떤 일을 하는 코드 묶음?인데 이름이 없음
주로 변수에 저장해서 쓰거나 다른 함수에 넘겨줘서 사용함

굳이 ? 언제 씀 ?

  1. 코드를 “저장”해서 “나중에” 쓰고 싶을 때
func after1Second(task: @escaping () -> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: task)
}

after1Second {
    print("1초 뒤에 실행됨!")
}

@escaping으로 지금 print를 실행하는 게 아니라, 1초 뒤에 실행되게 전달한 거.
지금 말고 나중에 해줘 ~~~ .. 인 느낌.
코드를 값처럼 다룰 수 있어서, 나중에 실행하거나 전달하기 좋은 듯

  1. 동작을 넘겨주기 좋음
func doSomethingBeforeWork(work: () -> Void) {
    print("밥 먹기 전")
    work()
}

doSomethingBeforeWork {
    print("손 씻기")
}

이런 식으로 함수에 다른 동작을 전달할 수 있음

  1. 코드를 간결하게 만들 수 있음
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 같은 변수)을 들고 가서 기억하고 쓸 수도 있는 ??

함수랑 비슷하면서도 다르고, 눈에 보이지 않는 복잡한 동작이 숨어있어서

어렵다고 느껴지는 듯 함.. 클로저에 대해 좀 깊게 톺아보았던 것 같음 !!

0개의 댓글