일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- singleton
- http
- self
- array
- viewlifecycle
- SWIFT
- protocol
- Git
- apns
- Switch
- Refresh
- 고차함수
- escaping
- Observer
- IOS
- SWIFTUI
- list
- NotificationCenter
- segue
- class
- struct
- error
- uikit
- PushNotification
- ScrollView
- mvvm
- 글또
- 회고
- 화면전환
- calendar
- Today
- Total
seong_hye, the developer
Swift) 문법 정리 - 클로저 (Closure) 본문
📘 Swift 문법 정리: 클로저(Closure)
Swift 문법 중 클로저에 대해 정리한 글입니다.
Swift를 공부하다 새로운 기술을 많이 보게 되는데
가장 흥미롭게 공부하는데 시간이 꽤 걸린 클로저에 대해 알아보려고 합니다.
🔹 문법 설명
클로저를 한마디로 정의한다면 익명함수라고 할 수 있습니다.
함수에서 이름을 땐 기능 블록을 의미합니다.
하지만, 사실은 func 키워드를 이용해 이름이 붙어있는 함수들도 모두 클로저라고 합니다.
📌 이름이 있는 클로저(Named Closure) + 이름이 없는 클로저(Unnamed Closure) = 클로저 (Closure)
여기서 우리는 Named Closure 를 함수라고 부르고 있으며
Unnamed Closure를 클로저라고 말합니다.
클로저가 함수보다 큰 범위인 것이죠!(포함관계)
func doSomthing() { //이름이 있는 클로저(Named Closure)
print("hi")
}
let closure = { print("Hi") } // 이름이 없는 클로저(Unnamed Closure)
일급객체로 취급되는 코드 블록으로 일반 함수처럼 인자와 반환값을 가질 수 있지만 이름 없이 사용할 수 있습니다.
또한 핵심 기능으로 주변의 값을 **캡처하여 저장** 할 수 있습니다.
일급 객체란?
프로그래밍 언어에서 다음 3가지 조건을 모두 만족하는 대상을 말합니다.
1. 변수나 상수에 저장할 수 있음
2. 함수의 인자로 젼달할 수 있음
3. 함수의 반환값으로 사용할 수 있음
let closure = { () -> () in
print("closure")
}
let closrue2 = closure // 변수나 상수에 저장할 수 있음
func doSomething(clousre: () -> ()) {
closure()
}
doSomething(closure: { () -> () in // 함수의 인자로 젼달할 수 있음
print("Hello")
})
func doSomething() -> () ->() {
return { () -> () in // 함수의 반환값으로 사용할 수 있음
print("Hello")
}
}
let closure = doSomething()
closure()
🔹 클로저 문법 설명
{ (Parameters) -> Return Type in
//실행구문
}
let closure = { (name: String) -> String in
return "Hello, \(name)"
}
closure("Seonghye")
closure(name:"Seonghye") // Error
📌 설명
- in 키워드 앞은 파라미터 / 리턴타입 작성
- in 뒤는 실제 실행될 코드를 작성
- 타입은 컴파일러가 추론 가능
- 실행 코드가 한 줄일 경우 return도 생략 가능
🔹 함수에 클로저 전달하기
func perform(action: () -> Void) {
print("시작")
action()
print("끝")
}
perform {
print("클로저 실행")
}
// 실행 결과
시작
클로저 실행
끝
📌 후행 클로저 문법
클로저가 마지막 인자일 경우, 함수 밖 중괄호로 작성 가능한 기능입니다.
단순한 문법적 편의 그 이상으로 가독성과 표현력을 높일 수 있어 사용하게 됩니다.
SwiftUI에서 사용되는 아래 코드도 내부적으로 후행 클로저 문법입니다.
즉 Swift의 코드 스타일과 DSL 구조에 최적화된 기능입니다.
VStack {
Text("Hello World")
}
🔹 클로저의 캡처 기능
클로저는 자신이 생성될 때, 외부 스코프에 있는 변수나 상수를 "캡처"해서 나중에도 사용할 수 있도록 저장한다
즉, 클로저가 선언될 당시의 변수 상태를 기억하고 유지합니다.
이 변수는 클로저가 사라질 때까지 함께 살아있게 됩니다.
func makeCounter() -> () -> Int {
var count = 0
return {
count += 1
return count
}
}
let counter = makeCounter()
print(counter()) // 1
print(counter()) // 2
📘 해설
- count 는 makeCounter() 함수 안에 있는 지역 변수입니다.
- 하지만 return 한 클로저는 count를 캡처하게 됩니다.
- makeCounter()는 호출이 끝났지만, 클로저 덕분에 count는 계속 살아 있게 됩니다.
즉, 클로저가 count를 메모리에 유지하고 있기 때문에 가능한 코드입니다.
📌 포인트
- 클로저는 함수 외부의 변수를 캡처해서 계속 사용이 가능하다
- 변수의 값을 유지한다는 점에서 일반 함수와 다르다.
⚠️주의할 점!
클로저의 캡처 => 메모리 누수 가능
클로저가 self를 캡처할 경우, 강한 참조 순환(Retain Cycle)이 발생할 수 있습니다.
이 경우를 해결하기 위해 [weak self] or [unowned self]를 사용합니다.
class MyClass {
var name = "Swift"
func startTask {
someAsyncFunction {
print(self.name) // slef 캡처 -> 메모리 누수 위험
}
}
}
-------해결 방안
someAsyncFunction { [weak self] in // [weak self] or [unowned self]를 사용
print(self?.name ?? "")
}
🔹 @escaping 클로저
func fetchData(completion: @escaping (String) -> Void) {
DispatchQueue.global().async {
completion("데이터 도착")
}
}
📌 설명
- 클로저가 함수 실행이 끝난 후에 실행해야하는 경우 @escaping 필요
- 보통 비동기 작업에 사용됨
🔹 고차함수에서의 클로저 활용
let numbers = [1,2,3,4,5]
let doubled = numbers.map {$0 * 2}
print(doubled)
📌 포인트
- map, filter, sorted 같은 함수는 내부에 클로저를 사용한다.
- Swift의 함수형 프로그래밍 문법에서의 핵심이다.
📘 마무리 요약
- 클로저는 이름 없는 함수
- in 을 기준으로 파라미터/ 코드 분리
- 외부 변수 캡처, @escaping, 메모리 관리까지 다양하게 사용됨
'IOS' 카테고리의 다른 글
Swift) 문법 정리 - inout 키워드 (0) | 2022.07.19 |
---|---|
Swift)문법 정리 - 고차함수 (0) | 2022.07.12 |
Swift) 문법 정리 - 에러 처리(Error Handling) (0) | 2022.07.12 |
Swift) 문법 정리 - 열거형(Enum) (0) | 2022.07.12 |
Swift) 문법 정리 - 프로토콜 (0) | 2022.07.12 |