[Swift] 클로저 [1]

임승섭·2023년 6월 27일
0

Swift

목록 보기
16/35

Review - 함수 타입의 표기

  • () -> () () -> Void
  • (String) -> String
  • (Int, Int) -> () (Int, Int) -> Void
// 함수의 타입 표기법
let functionA: (String) -> String      // 1)파라미터 문자열, 2)리턴형 문자열
// 메모리 공간만 만들어두고, 실제로 할당하진 않았다
// "이러한 형태의 함수 타입을 담을 수 있다"

let functionB: (Int) -> ()             // 1)파라미터 정수, 2)리턴형 없음

let functionC: (String) -> Void        // 1)파라미터 문자열, 2)리턴형 없음

클로저

  • 이름이 없는 함수
  • 클로저와 함수는 기능이 동일하지만 형태는 다르다
  • C언어에서 Block
  • 함수 : 이름이 있는 코드 묶음
    • 다른 코드가 함수 이름으로 호출
  • 클로저 : 이름이 없는 코드 묶음
    • 이름이 없어도 호출할 수 있는 형태
  • 함수의 형태
    func myFuntion() -> Int {
        return ...
     }
  • 클로저의 형태
    { () -> Int in
        return ...
     }
    • 중괄호를 보면 이제 함수라고 생각하자
// 함수의 정의
func aFunction(str: String) -> String {
    return "Hello, \(str)"
}

// 클로저의 형태
let _ = { (str: String) -> String in
    return "Hello, \(str)"
}
// 중괄호가 앞으로 오고, 원래 자리에 in 써준다
// 와일드카드 패턴 그냥 쓴거야. 할당 안하면 클로저는 아무것도 못한다
  • 스위프트는 함수를 1급 객체로 취급한다 (프로토콜 내용과 동일)
    즉, 함수는 타입이다.
    1. "함수"를 변수에 할당할 수 있다
    2. 함수를 호출할 때, "함수"를 파라미터로 전달할 수 있다
    3. 함수에서 "함수"를 반환할 수 있다
// 함수 정의
func aFunction1(_ param: String) -> String {
    return param + "!"
}


func aFunction2(name: String) -> String {
    return name + "?!??"
}



// 1). 함수를 변수에 할당가능(변수가 함수를 가르키게 됨)
// aFunction1() : 소괄호까지 써버리면 함수의 "실행"
// aFunction1   : 소괄호 안쓰면 그냥 함수를 가리킨다
var a: (String) -> String = aFunction1		// 타입을 지워도 된다
// a라는 변수에 함수가 들어있다!
a("안녕")		// 소괄호 써서 실행 가능


/*===== 일반적으로 이런 식으로 함수를 실행할 때는 parameter의 이름이 필요 없다 =====*/


// 새로운 함수를 담는다
a = aFunction2		// 위에서 명시한 타입과 aFunction2의 타입이 동일하기 때문에 가능
					// 타입이 다르면 담을 수 없다!!
                    // 다른 함수를 '가리키게' 된다
a("hello")			// 함수 실행 시 parameter 이름을 써주지 않아도 된다


// 1). 함수(클로저)를 변수에 할당해서 사용(실행)
let closureType = { (param: String) -> String in         // 클로저 리터럴
    return param + "!"
}
closureType("스티브")		// "스티브!"

형태

  • 함수

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

    // 와일드카드 패턴(_)은 신경쓰지 말자. 클로저만 써두면 에러나서 그냥 써둔거
    let _ = { (a: Int, b: Int) -> Int in
        let result = a + b
        return result
    }
  • 클로저 (타입 추론이 가능한 경우)

    let _: (Int, Int) -> Int = { (a, b) in
        let result = a + b
        return result
    }
  • 클로저 (리턴형 생략)

let aClosure1 = { (str: String) in	// output 타입을 생략할 수 있다
	return "Hello, \(str)"			// 컴파일러가 추론할 수 있기 때문
}

let aClosure2: (String) -> String = { (str) in	// input 타입을 생략할 수 있다 (미리 타입 선언)
	return "Hello, \(str)"
}

let aClosure3 = {					// () -> () 생략 가능
	print("This is a closure.")
}

let aClosure4 = { param in			// 걍 다 생략
	return param + "!"				// 컴파일러가 타입 추론이 가능 (더하거나 빼기는 같은 타입끼리만 가능)
}

클로저를 사용하는 이유

클로저 : 이름이 없는 함수

  • 이름이 왜 필요없냐

  • 함수를 실행할 때 전달하는 형태로 사용하기 때문에 이름이 필요 없다

    // 1. (클로저를 파라미터로 받는) 함수 정의
    func closureParamFunction(closure: () -> Void) {
        print("프린트 시작")
        closure()
    }
    	
    // 2. 함수 실행할 때 (파라미터를 클로저 형태로 전달)
    closureParamFunction(closure: {
        print("프린트 종료")
    } )
    	
    	
    /* closureParamFunction 함수를 호출하면서 클로저를 전달 */
    
    // 일반적으로 파라미터 타입이 함수로 되어있는 함수를 실행할 때,
    // 클로저 형태로 전달한다
    // 왜냐면 이름이 굳이 필요가 없으니까!

클로저를 사용하는 이유

  • 1). 클로저를 파라미터로 받는 함수를 정의한다
  • 2). 함수를 실행할 때 파라미터를 클로저 형태로 전달한다
    (기존에 정의한 함수를 쓰는게 아니고, 파라미터 안에서 클로저 형태로 하나 정의해서 바로 전달)
  • 사후적으로 클로저를 정의할 수 있다 -> 엄청난 장점!!
/*-----------------------Ex. 1-----------------------*/
// 1). (클로저를 파라미터로 받는 함수) 정의
func closureParamFunction(closure: () -> ()) {	// 매개변수 함수의 이름 : closure
    print("프린트 시작")
    closure()				// 소괄호를 붙여서 함수를 **실행**시킨다.
}


// 파라미터로 사용할 함수/클로저를 정의
func printSwiftFunction() {          // 함수 형태로 정의
    print("프린트 종료")
}
let printSwift = { () -> () in      // 클로저 형태로 정의
    print("프린트 종료")
}

// 기존에 배운 형태로 함수 실행 (매개변수로 '함수'를 주면 된다)
closureParamFunction(closure: printSwiftFunction)
closureParamFunction(closure: printSwift)



// 2). ⭐️ 파라미터를 클로저 형태로 전달
closureParamFunction(closure: { print("프린트 안녕안녕안녕") } )		// input output 생략
// 클로저를 정의하면서 파라미터로 전달해버렸다

closureParamFunction(closure: { () -> () in
    print("프린트 종료")           // 본래 정의된 함수를 실행시키면서, 클로저를 사후적으로 정의 가능
})                              // (활용도가 늘어남)

closureParamFunction(closure: { () -> () in
    print("프린트 종료 - 1")
    print("프린트 종료 - 2")
})
/*---------------------------------------------------*/


/*----------------------Ex. 2-----------------------*/
// 1) (클로저를 파라미터로 받는 함수) 정의
func closureCaseFunction(a: Int, b: Int, closure: (Int) -> Void) {
    let c = a + b
    closure(c)
}


// 2) ⭐️ 함수를 실행할 때 (클로저 형태로 전달)
closureCaseFunction(a: 5, b: 2, closure: { (n) in    // 사후적 정의
    print("이제 출력할게요: \(n)")
})

closureCaseFunction(a: 5, b: 2) {(number) in         // 소괄호 땡기는 문법
    print("출력할까요? \(number)")
}

closureCaseFunction(a: 5, b: 3) { (number) in        
    print("출력")
    print("출력")
    print("출력")
    print("값: \(number)")
}
/*---------------------------------------------------*/


/*-----------------------Ex. 3-----------------------*/
// 1). 함수의 정의
func multiClosureFunction(closure1: () -> Void, closure2: () -> Void) {
    closure1()
    closure2()
}

// 클로저 정의
let print1 = { print("1") }
let print2 = { print("2") }
let print3 = { print("3") }


// 2). 함수의 실행
multiClosureFunction(closure1: print1, closure2: print2)
multiClosureFunction(closure1: print2, closure2: print3)

multiClosureFunction(closure1: {
    print("1")
}, closure2: {
    print("2")
})
/*---------------------------------------------------*/


/*-----------------------Ex. 4-----------------------*/
// 1). 함수의 정의
func performClosure(closure: () -> ()) {
    print("시작")
    closure()
    print("끝")
}

// 2). 함수의 실행
performClosure(closure: {
    print("중간")
})

0개의 댓글