swift study 18. 클로저(Closures)

jess·2022년 7월 29일
0

Swift

목록 보기
18/19
post-thumbnail

🍃 출처 : 앨런 swift 문법 마스터 스쿨 수업을 듣고 제가 이해한대로 정리해서 올리는 포스팅입니다.

📓 클로저(Closures)

1) 클로저의 개념 및 1급 객체 취급의 의미

  • 클로저 : 이름이 없는 (익명) 함수
  • 클로저와 함수는 기능이 완전히 동일한데, 형태만 다르다고 생각하면 됨
  • 클로저는 함수보다 조금 더 큰 범위라고 생각하면 됨
    함수 : 이름이 있는 코드 묶음 ➡️ 다른 코드가 함수이름으로 호출하기 위함
    클로저 : 이름이 없는 코드 묶음 ➡️ 굳이 이름이 없어도 호출할 수 있는 형태로 사용 가능

2) 함수와 클로저의 형태

✨ 함수

func add(a: Int, b: Int) -> Int {
    let result = a + b
    return result
}

✨ 클로저

{ (a: Int, b: Int) in
    let result = a + b
    return result
}
{ (a,b) in
    let result = a + b
    return result
}

{ (파라미터) -> 리턴형 in
let result = a + b
return result
}

  • 스위프트는 함수를 일급객체로 취급
  • 함수는 타입이다
    1) 함수를 변수에 할당할 수 있음
    2) 함수를 호출할 때, 함수를 파라미터로 전달할 수 있음
    3) 함수에서 함수를 반환할 수 있음

3) 클로저를 사용하는 이유

  • 함수를 실행할 때 전달하는 형태로 사용하기 때문에 이름이 필요 없음
// (1) (클로저를 파라미터로 받는) 함수를 정의 :
func closureParamFunction(closure: ( ) -> Void) { print(“프린트 시작”)
closure( ) }
// (2) 함수를 실행할 때 (파라미터를 클로저 형태로 전달)
closureParamFunction(closure: { print(“프린트 종료”)
})
  • closureParamFunction을 실행할 때, "프린트 종료"라는 것을 출력하는 클로저를 전달
  • 이렇게 사후적으로 클로저 형태로 정이를 하며 전달을 할 수 있음
    ➡️ 활용도가 매우 커짐, 커스터마이징 할 수 있는 것이 늘어남
  • 파라미터로 전달하는 클로저가 기존의 함수 내용이 다 실행되고 나서 실행된다고 봐도 무방
  • ⭐️ 콜백함수 : 함수를 실행할 때 파라미터로 전달하는 함수

ㅡA

4) 클로저의 문법최적화

1. 후행 (Trailing) 클로저

// 원래 형태
closureParamFunction(closure: { print(“프린트 종료”)
})
// 후행 클로저 형태 
closureParamFunction { print(“프린트 종료”)
}
  • 함수의 마지막 전달인자(아규먼트)로 클로저가 전달되는 경우 소괄호 생략 가능

2. 파라미터 및 생략 등의 간소화

// 정식 문법
performClosure(closure: { str in return str.count
})
// 클로저 간소화 문법
performClosure { $0.count 
 // * $0 : 첫 번째 파라미터, $2, 두 번째 파라미터
{ (a, b) in
return a*b
}
⬇️
{ $0*$1 }
  • 한 줄일때 리턴 생략 가능

3. 멀티플 후행 클로저

// 정의
func multiple(first: , second: , third: ) { first( )
second( )
}
// 사용시
multiple { print(“프린트 - 1)
} second: { print(“프린트 - 2)
} third: {
print(“프린트 - 3)
}

5) 클로저의 메모리구조

  • 타입 : Reference Type
  • 메모리 상의 저장 위치 : 필요시에 항상 메모리의 주소를 전달
  • 값의 저장 : heap (주소를 stack에 저장)
  • 메모리 관리 방식 : RC를 통해 메모리를 관리, swift에서 사용하는 ARC모델

6) 클로저의 캡쳐현상

예제1

func calculate(number: Int) -> Int {
    
    var sum = 0
    
    func square(num: Int) -> Int {
        sum += (num * num)
        return sum
    }
    let result = square(num: number)
    
    return result
}


calculate(number: 10) //100
calculate(number: 20) //400
calculate(number: 30) //900

예제2

func calculateFunc() -> ((Int) -> Int) {
    
    var sum = 0
    
    func square(num: Int) -> Int {
        sum += (num * num)
        return sum
    }
    return square
}
var calculate = calculateFunc()
calculate(10)  //100
calculate(20)  //500
calculate(30)  //1400
  • 두 예제의 다른 점은 무엇일까 ?
    예제2의 square는 함수를 실행하는 것이 아니고 함수를 가리키고 있다.
    var calculate = calculateFunc() 를 하면서 square함수를 리턴하는 것
    즉 내부의 함수를 꺼내서 변수에 담는 순간 메인함수에 변수가 생기고,
    함수가 실행이 되며 스택프레임이 생긴다
    스택프레임은 내부에 있는 함수를 꺼내서 리턴해야 한다 (중첩함수)
    외붑 변수를 지속적으로 사용해야하기 때문에 일어나는 것이 바로 캡쳐현상

7) @escaping / @autoclosure 키워드

✨ @escaping 키워드

  • 1) 어떤 함수의 내부에 존재하는 클로저(함수)를 외부 변수에 저장
  • 2) GCD (비동기 코드의 사용)
var aSavedFunction: () -> () = { print("출력") }
//aSavedFunction()
func performEscaping2(closure: @escaping () -> ()) {
    aSavedFunction = closure         
    // 클로저를 실행하는 것이 아니라  aSavedFunction 변수에 저장
    //closure()
}
//aSavedFunction()
performEscaping2(closure: { print("다르게 출력") })
//aSavedFunction()

✨ @autoclosure 키워드

  • 자동으로 클로저를 만들어주어 (자동 중괄호) 타입만 제공하면 됨
// 클로저 앞에 @autoclosure 키워드 사용(파라미터가 없는 클로저만 가능)

func someFuction(closure: @autoclosure () -> Bool) {
    if closure() {
        print("참입니다.")
    } else {
        print("거짓입니다.")
    }
}

var num = 1

ㅡB

0개의 댓글