ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Swift #13 - 클로저
    Swift의 온도 2021. 1. 21. 01:49

     

    1. 클로저와 함수 타입

     

    - 클로저

     

    #클로저란?

     *클로저는 함수 객체

     *클로저 형태 : 함수나 코드 블록

     *클로저가 정의된 콘텍스트까지 포함

     

    - 함수 객체

    *함수 정의
     
    func sayHello() {
        print("Hello")
    }
     
    *함수 호출
     
    sayHello()
     
    *함수 참조
     
    var hello = sayHello
    hello()
     
    *파라미터로 사용하기
     
    var hello = sayHello
    greet(hello)
     
    *함수 파라미터 정의?
     
    func greet(_ arg : ????) {
    }
    cs

     

    - 함수 타입

     *함수 객체를 참조 변수로 사용할 때의 타입

     *파라미터로 사용할 때

     *함수 타입 : 함수의 구성 요소인 파라미터, 반환 타입으로 구성

     

    #함수 타입의 예시

    *파라미터 없고, 반환 값 없는 함수 : () -> ()
     
    func sayHello() {}
     
    *()대신 Void 사용 가능 : () -> Void
    cs
    *파라미터 없고, 반환 값 없는 함수 : () -> ()
     
    func sayHello() {}
     
    *()대신 Void 사용 가능 : () -> Void
    *파라미터와 반환 값이 없는 함수 타입
     
    *(String- > ()
     
    func sayByeBye(who : String) {}
     
    *(StringString-> ()
     
    func say(who : String, what : String){}
     
    *파라미터와 반환 타입이 있는 함수 타입
    *(IntInt-> Int
     
    func add(i : int, j : Int-> Int {
        return i + j
    }
    cs

     

    #같은 타입의 함수

    *다음 두 함수는 같은 함수 타입 : (IntInt-> Int
     
    func add(i : Int, j : Int-> Int {
        return i + j
    }
    func multiply(i : Int, j : Int-> Int {
        return i * j
    }
    cs

     

    - 클로저 사용하기

    #클로저를 사용하는 API

    *Array의 sort 메소드, 파라미터 타입
     
    func sorted(by order : (Element, Element) -> Bool-> [Element]
     
    *Array<Int>의 경우 : (IntInt-> Bool
    *함수 타입에 맞는 함수
     
    func sortFunc(a : Int, b : Int-> Bool {
        return a < b
    }
     
    *Array의 sort 함수에 사용하기
     
    let sorted = array.sorted(by : sortFunc)
    cs

     

    - 클로저 표현식

    *별도의 함수 정의 없이 Inline 방식으로 작성
     
    {( PARAMETERS) -> RETURN_TYPE in
     //코드
    }
     
    *예시
     
    array.sorted(by:{(a : Int, b : Int-> Bool
    in
        return a < b
    })
    cs

     

    #클로저 표현식 단축

    *타입 선언 생략
     
    array.sorted(by: { a,b -> Bool in return a < b } )
     
    *1줄 return 인 경우 -> return 생략
     
    array.sorted(by: { a,b -> Bool in a < b } )
     
    *반환 타입 선언 생략
     
    array.sorted(by: { a,b in a < b})
     
    *파라미터 선언 생략
     
    array.sorted(by: { $0 < $1 })
    cs

     

    - 클로저 축약

    #Tailing Closure

    *클로저 파라미터가 마지막인 경우
    *괄호 밖에 작성
    *외부 파라미터 사용 생략
     
    array.sorted(by: { a, b in a a < b } )
    array.sorted(){ a, b in a < b } )
     
    *파라미터가 클로저 1개 -> 괄호식도 생략
     
    array.sorted { a, b in a < b}
    cs

     

    2. 클로저 API 작성하기

     

    - 클로저 사용 API

    #클로저를 사용하는 API 작성하기

     *클로저의 함수 타입 결정

     *반환 값으로 사용

     *파라미터로 사용

     *프로퍼티에 사용

     

    #반환 값으로 정의하기

    *반환 값의 함수 타입 : () -> ()
     
    func greeting() -> () -> () {
        func sayGoodmorning() {
            print("Good Morning")
        }
        return sayGoodmorning
    }
     
    *호출
     
    let ret = greeting()
    ret()
     
    *클로저 표현식으로 작성하기
     
    func greeting() -> (() -> ()) {
        return { () -> () in
            print("How are you?")
        }
    }
     
    *축약하기
     
    func greeting() -> () -> () {
        return {
            print("How are you?")
        }
    }
    cs

     

    #파라미터에 사용하기

    *기존 함수
     
    func add(_ i : Int _ j : Int-> Int {
        let sum = i + j
        return sum
    }
     
    let ret = add(1,2)
     
    *함수파라미터로 선언
    *함수 내부에서 호출
     
    func add(_ i : Int _ j : Int, _ handler: (Int-> Void ) {
        let sum = i + j
        handler(sum)
    }
     
    *사용하기
     
    add(34, { (result : Int-> Void in
        print("3 + 4 = \(result)")
    })
     
    *파라미터 타입 선언 생략, 반환 타입 선언 생략
     
    add(34, { result in
        print("3 + 4 = \(result)")
    })
     
    *파라미터 선언 생략, Trailing Closure
     
    add(34, { ( result in
        print("3 + 4 = \(result)")
    }
    cs

     

    - 클로저 사용 API

    #클로저와 옵셔널

    *파라미터 타입 : 클로저 옵셔널
     
    func multiply(_ i : Int _ j : Int,
            _ handler : ((Int-> Void)?)
     
    *반환 타입 : 클로저 옵셔널
     
    func sayHello() -> (() -> ())? {
        return nil
    }
    cs

     

    #프로퍼티로 클로저

    *클래스 프로퍼티 타입으로 함수 타입
     
    class MyClass {
        var property : ( () -> Int )!
    }
     
    *프로퍼티에 값(클로저) 설정
     
    var obj = MyClass()
    obj.property = {
        return 0
    }
    cs

     

    - 커스텀 타입 내 접근

    #클로저에서 프로퍼티 접근

    *클로저에서 프로퍼티 접근 : self 사용
     
    class MyClosureClass {
        var value = 0
     
        func showAndPrint() -> () -> () {
            return {
                print(self.value)
            }
        }
    }
    cs

     

    3. 클로저와 캡처

     

    - 클로저

    #클로저 : 함수 + 객체

     *클로저 생성 환경 ! = 클로저 실행 환경

     *클로저가 정의된 환경(컨텍스트)을 캡처(Capture)

     

    - 클로저 컨텍스트

    *클로저 정의된 부분에서 접근 가능한 객체 (읽기)
     
    func greeting() -> () -> () {
        let str = "Hello"
        return {
            print(str)
        }
    }
     
    *호출하기 - 출력되는 str의 값은?
     
    let str = "Good Morning"
    let ret = greeting()
    ret()
    cs

     

    #클로저 캡처

    *값 변경하기
     
    func increment(by amount : Int-> () -> () {
        var count = 0
        return
            count += amount
            print(count)
        }
    }
    cs

     

    - 레퍼런스 타입 캡처

    #레퍼런스 타입 객체 캡처

    *클래스 정의
     
    class MyClass {
        var value = 0
    }
     
    *클로저
     
    func increment2(by amount : Int-> () -> () {
        let obj = MyClass()
        return {
            obj.value += amount
            obj.printValue()
        }
    }
    cs

     

    4. escaping, autoclosure

     

    - escaping, noescaping

    #noescaping

    *함수 파라미터로 클로저 전달
    *함수 외부에 사용 금지(기본값)
    *프로퍼티로 설정 - 에러
     
    class MyClass {
        var prop : (() -> ())!
        func closureFunc(_ arg : () -> () ) {
        }
    }
     
    *다른 함수 파라미터로 호출 : 가능
    *noescaping -> noescaping 으로 전달 가능
     
    func closureFunc(_ arg : () -> () ) {
        otherFunc(arg)
    }
     
    func otherFunc(_ arg : () -> () ) {
        arg()
    }
    cs

     

    #escaping

    *파라미터 타입에 @escaping 작성
    *파라미터 클로저를 함수 외부에 사용하기
     
    class MyClass2 {
        var prop : (() -> ())!
        func closureFunc(_ arg : @escaping () -> () ) {
            self.prop = arg
        }
    }
    cs

     

    #escaping 파라미터

    *noescaping에서 escaping 함수 파라미터 대입은 불가
     
    func closureFunc(_ arg : () -> () ) {
        otherFunc(arg) // Error
    }
     
    func otherFunc(_ arg : @escaping () -> () ) {
        arg()
    }
    cs

     

    - autoclosure

    #autoclosure

    *파라미터가 없는 표현식을 클로저로 변환
    *파라미터가 없는 클로저
     
    func dolt(_ arg : () -> () ) { // Code }
    dolt( {value += 10} )
     
    *Auto Closure - 파라미터
     
    func dolt2(_ arg : @autoclosure () -> () ) { // Code }
    dolt2( value += 10 )
    cs

     

    #autoclosure는 모두 noescape

    *autoclosure를 escaping 으로 선언하기
     
    var escapedVar : (() -> () )!
    func dolt3(_ arg : @autoclosure @escaping () -> () ) {
        arg()
        escapedVar = arg
    }
     
    dolt3( value += 10 )
    cs

    'Swift의 온도' 카테고리의 다른 글

    Swift #15 - 에러처리  (0) 2021.01.26
    Swift #14 - 프로토콜, extension  (0) 2021.01.22
    Swift #12 - 구조체와 Enum  (0) 2021.01.20
    Swift #11 - 메모리 관리  (0) 2021.01.19
    Swift #10 - 상속  (0) 2021.01.15

    댓글