일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- RxCocoa
- rxswift
- MVVM
- UITextView
- map
- Human interface guide
- tableView
- Protocol
- 클린 코드
- collectionview
- ios
- swiftUI
- uiscrollview
- 스위프트
- swift documentation
- Observable
- UICollectionView
- uitableview
- 리펙터링
- ribs
- Refactoring
- SWIFT
- 리팩토링
- 리펙토링
- HIG
- clean architecture
- Xcode
- combine
- Clean Code
- 애니메이션
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[swift] 7. 클로저(closure) 본문
1. 클로저표현식 : 익명함수, 주변 환경으로부터 값을 "캡쳐"(휘발성인 지역변수의 값이 저장되는 것)할 수 있는 경량 문법
즉, 클로저라는 것은 리턴된 타입(어떤 함수의 종료)을 참조할 때, 함수가 이미 종료된 시점에서 특정 변수를 참조하는 것
- 클로저표현식은 익명함수로 생각하면 편함
- func키워드, 함수이름 제거한 후 나머지만 표현
1) 기본 사용법
// 대입 후 실행
let a = { (v1: Int, v2: Int) -> Void in
print("value1 = \(v1), value2 = \(v2)")
}
a(1,2)
// 바로 실행
({ (v1: Int, v2: Int) -> Void in
print("value1 = \(v1), value2 = \(v2)")
})
2) 생략
// 정석
let a = { (v1: Int, v2: Int) -> Int in
return v1 + v2
}
print(a(1,2))
// 반환타입 생략
let b = { (v1: Int, v2: Int) in
return v1 + v2
}
print(b(2,4))
// 매개변수 타입 생략
let c = { (v1, v2) -> Int in
return v1 + v2
}
print(c(1,2))
// $사용
let d = {
return $0 + $1
}
- 생략시, 매개변수타입이나 반환타입 둘 중 하나는 반드시 선언해야함
2) 트레일링 클로저(Trailing Closure)
- 마지막 인수가 함수일 때 클로저 이용
func plus(base: Int, success s: () -> Void) -> Int {
s()
return 100 + base
}
// 매개변수 타입, 반환타입 생략된 트레일링 클로저
plus(base: 10) { () in
print("success!!")
}
3) 어노테이션
- @escaping : 원래 캡쳐 기능을 못하게 해놓았지만, 이 어노테이션을 이용하면 참조가능
- 인자 타입 앞에다 선언
func callback1(fn: () -> Void) {
let f = fn // error : Non - escaping prameter 'fn' may only be called
f()
}
// 어노테이션 적용
func callback2(fn: @escaping () -> Void) {
let f = fn
f()
}
callback2{
print("success!!")
}
- 탈출불가의 이점은 컴파일러의 최적화 (해당 클로저가 탈출 할 수 없다는 것은 컴파일러가 더 이상 메모리 관리상의 신경쓸 필요 없다는 것)
- 탈출불가 클로저에서는 self키워드 사용 가능(해당 함수가 끝나서 리턴되기 전에 호출될 것이 명확하기 때문)
- @autoclosure : {} 대신에 ()사용할 수 있게끔 함
func condition(stmt: @autoclosure () -> Bool) {
if stmt() == true {
print("true")
} else {
print("false")
}
}
condition(stmt:
1 > 3
)
// @autoclosure가 없다면 condition(stmt:
condition{ () in
1 > 3
}
2. capture list
1) 개념
Strong Reference Cycle을 해결하기 위해서, 클로저에서 weak, unowned를 사용할 수 있는 문법
클로저에서 '{'의 오른쪽에, 'in'의 왼쪽에 '[참조타입의 변수]'형태로 표현
ex) 참조타입인 t는 내부
class Test {
var a = 10
}
func ex(completion: (Int) -> ()) {
print("ex")
completion(10)
}
var t = Test()
self.ex { [t] (val) in
print(val)
}
2) caption list를 사용하는 이유
var index = 0
var closureArr: [() -> ()] = []
for _ in 1...5 {
closureArr.append({print(index)}) /// print(index)라는 함수 삽입
index += 1
}
for i in 0..<closureArr.count {
closureArr[i]()
}
위의 결과는?
0, 1, 2 ,3, 4가 아닌 5,5,5,5,5
1에서 5까지 돌면서 최종적으로 변경된 index값은 5이며, 클로저가 참조하고 있는 값은 바로 "index"변수이고 index값은 현재 5이므로
아래와 같이 수정하면 결과 : 0, 1, 2, 3, 4
var index = 0
var closureArr: [() -> ()] = []
for _ in 1...5 {
closureArr.append{[index] in
print(index)} /// print(index)라는 함수 삽입
index += 1
}
for i in 0..<closureArr.count {
closureArr[i]()
}
* 캡쳐 시점 : 값 타입은 클로져가 생성될 때 캡쳐, 참조 타입은 클로져가 호출될 때 캡쳐
3) 참조타입의 성질 설정(reference type인 경우만 사용가능)
ARC해결 여기 참고
(1) Strong Capture
참조 카운트 증가
- 순환참조의 문제점 발생 주의
(2) Weak Capture
참조 카운트를 증가시키지 않음
참조 대상이 nil일 수 있다는 Optional형태
(3) Unowned Capture
nil일수 없다는 확신, nil일시 강제종료
'swift 5 문법' 카테고리의 다른 글
[swift] 9. 상속 및 다운캐스팅 (0) | 2020.03.28 |
---|---|
[swift] 8. 구조체(struct)와 클래스(class), 프로퍼티 (0) | 2020.03.27 |
[swift] 6. 함수(일급 함수) (0) | 2020.03.26 |
[swift] 5. 옵셔널(Optional) (0) | 2020.03.26 |
[swift] 4. 배열(Array), 집합(Set), 튜플(Tuple), 딕셔너리(Dictionary) (0) | 2020.03.25 |