Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- UITextView
- tableView
- clean architecture
- map
- uitableview
- MVVM
- 리펙터링
- Clean Code
- ribs
- uiscrollview
- swiftUI
- collectionview
- Xcode
- 클린 코드
- 리펙토링
- RxCocoa
- 리팩토링
- Observable
- HIG
- swift documentation
- 애니메이션
- rxswift
- SWIFT
- 스위프트
- UICollectionView
- Protocol
- ios
- Human interface guide
- combine
- Refactoring
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift 공식 문서] 7. Closure (클로저) 본문
Closure
- Closure(폐쇄): 클로저는 코드에서 전달 및 사용할 수 있는 2가지의 자체 기능을 가진 블록
- 정의된 컨텍스트에서 모든 상수 및 변수에 대한 참조를 캡쳐하고 저장 가능
- 캡쳐: 자신의 블록 외부에 있는 값을 참조하는 것
// ex) 캡쳐: incrementer() 함수 블록에서 runningTotal과 amount인수를 참조
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
Closure는 실행 순서 제어가능
- 클로저는 호출할 때까지 내부 코드가 실행되지 않기 때문에 적절한 타이밍에 사용 가능
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
customersInLine.count // "5"
let customerProvider = { customersInLine.remove(at: 0) }
customersInLine.count // "5"
customerProvider()
customersInLine.count // "4"
예시) 정렬 클로저
- sroted(by:): 함수 클로저를 전달하여 정렬 규칙 정의
- 함수 클로저 전달
func backward(_ s1: String, _ s2: String) -> Bool {
return s1 > s2
}
let arr = ["a", "x", "d"]
let sortedArr = arr.sorted(by: backward)
- Closure Expression (클로저 표현식): 함수를 따로 정의하지 않고 블록을 바로 전달
let sortedArr = arr.sorted(by: { (s1: String, s2: String) -> Bool in
return s1 > s2
})
- Closure Expression - 타입 추론
let sortedArr = arr.sorted(by: { s1, s2 in return s1 > s2 } )
- Closure Expression - retrun 생략
let sortedArr = arr.sorted(by: { s1, s2 in s1 > s2 } )
- Closure Expression - argument name 접근: $0, $1, $2...
let sortedArr = arr.sorted(by: { $0 > $1 } )
Trailing Closure
func someFunctionThatTakesAClosure(closure: () -> Void) {
}
someFunctionThatTakesAClosure(closure: {
})
someFunctionThatTakesAClosure() {
}
- 함수가 여러 클로저를 사용하는 경우: 첫 번째 trailing 클로저에 대한 argument label을 생략하고 나머지 trailing 클로저에 argument label 작성
// closure로 사용할 수 있는 parameter를 가진 함수 정의
func loadPicture(from server: Server, completion: (Picture) -> Void, onFailure: () -> Void) {
if let picture = download("photo.jpg", from: server) {
completion(picture)
} else {
onFailure()
}
}
// trailing closure로 사용: 첫 argument label만 생략
loadPicture(from: someServer) { picture in
someView.currentPicture = picture
} onFailure: {
print("Couldn't download the next picture.")
}
closure는 reference type
- 함수와 클로저는 reference type이기 때문에, incrementByTen() 호출마다 값이 누적되며 증가
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30
let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// returns a value of 7
@escaping closure
- escaping closure: 외부에서 closure를 참조하는 것
- cf) capture: 내부에서 외부를 참조하는 것
- ex) escaping closure
- 주로 비동기 작업을 시작하는 많은 함수는 completionHandler로 클로저 인수를 사용
- 함수는 작업을 시작한 후에 반환되지만 작업이 완료될 때까지 클로저가 호출되지 않으므로, 클로저를 나중에 호출하기 위하여 escaping closure를 사용
// @escaping을 선언하지 않은 경우 컴파일 에러 - 외부에서 closure를 참조하고 있기 때문
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
- 캡쳐 시 주의
- escaping closure는 self 명시적 선언 필요
- self가 필요한 이유: escaping은 해당 클로저가 외부로부터 참조 당했을 때, 캡쳐도 되는 상태면 reference cycle이 생길 수 있으므로 명시적 표현
- none escaping closure는 self 암시적 사용
- escaping closure는 self 명시적 선언 필요
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
func someFunctionWithEscapingClosure(closure: @escaping () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithNonescapingClosure {
x = 200 // 캡쳐
}
someFunctionWithEscapingClosure { [weak self] in
self?.x = 100 // 캡쳐
}
}
}
@autoclosure
- 인수를 받지 않으며 호출 될 때 내부 wrapping된 식을 반환하여 명시적 closure대신 일반 표현식을 작성하여 함수의 매개변수 주위에 블록을 생략하여 사용
- @autoclosure 키워드
- 인수가 자동으로 클로저로 변환되므로 괄호 '{}' 생략 가능
// customersInLine is ["Alex", "Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
// Prints "Now serving Alex!"
// customersInLine is ["Ewa", "Barry", "Daniella"]
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
// Prints "Now serving Ewa!"
* 참고
https://docs.swift.org/swift-book/LanguageGuide/Closures.html
'swift 공식 문서' 카테고리의 다른 글
[iOS - swift 공식 문서] 9. Structures and Classes (0) | 2021.06.25 |
---|---|
[iOS - swift 공식 문서] 8. Enumerations (열거형) (0) | 2021.06.24 |
[iOS - swift 공식 문서] 6. Functions (함수) (0) | 2021.06.23 |
[iOS - swift 공식 문서] 5. Control flow (흐름 제어) (0) | 2021.06.21 |
[iOS - swift 공식 문서] 4. Collection Types (컬렉션 타입) (0) | 2021.06.19 |
Comments