[Swift] 클로저 [2]

임승섭·2023년 6월 28일
0

Swift

목록 보기
17/35

문법 최적화

  1. 문맥 상 parameter와 return value 타입 추론 (Type Inference)
  2. 한 줄인 경우, return을 적지 않아도 된다 (Implicit Return)
  3. argument 이름 축약 (Shorthand Arguments) $0, $1
  4. 함수의 마지막 아규먼트로 클로저가 전달되는 경우, 소괄호 생략 (Trailing Closure)

Trailing Closure (후행 클로저 문법)

/*-----------------Ex 1-----------------*/
func closureParamFunction(closure : () -> Void) {	// 요 속에 있는거 : 콜백 함수
	print("프린트 시작")
    closure()
}

/*원래 실행*/
closureParamFunction( closure: { print("프린트 종료") })

/*1. 이거 가능 - 소괄호를 앞으로 땡겨*/
closureParamFunction(closure: ) {
	print("프린트 종료")
}

/*2. 이거 가능 - argument 생략*/
closureParamFunction() {
	print("프린트 종료")
}

/*3. 이거 가능 - 아예 소괄호까지 생략*/
closureParamFunction {
	print("프린트 종료")
}
// 이걸 보고 클로저를 인풋으로 주고 있다는 것을 알아야 한다!!



/*-----------------Ex 2-----------------*/
func closureCaseFunction(a: Int, b: Int, closure: (Int) -> Void) {
	let c = a + b
    closure(c)
}

closureCaseFunction(a: 5, b: 2) { number in
	print("출력할까요? \(number)")
}

Example

// 함수 정의
func performClosure(param: (String) -> Int ) {
	param("Swift")
}

// 1). 타입 추론 (Type Inference)
performClosure(param: { (str: String) -> Int in
	return str.count
})

performClosure(param: { str in 
	return str.count
})


// 2). 한줄인 경우, 리턴 생략 가능
performClosure(param: {str in
	return str.count
})

performClosure(param: {str in
	str.count
})

// 3). 아규먼트 이름 축약 ($0 : 첫 번재 파라미터, $1 : 두 번째 파라미터, ...)
performClosure(param: {
	$0.count
})

// 4). 트레일링 클로저
performClosure {
	$0.count
}

// 결국, 한 줄로까지 줄일 수 있다
performClosure { $0.count }

Example

/*-------------------------Ex 1-------------------------*/
let closureType1 = { (param) in 
	return param % 2 == 0	// output : bool 타입
    // 2로 나누는거 보니까 param이 Int -> 타입 추론 후 생략
}

let closureType1 = { $0 % 2 == 0 }
/*------------------------------------------------------*/


/*-------------------------Ex 2-------------------------*/
let closureType3 = { (a: Int, b:Int) -> Int in
    return a * b
}

let closureType3: (Int, Int) -> Int = { (a, b) in
    return a * b
}

let closureType3: (Int, Int) -> Int = { $0 * $1 }
/*------------------------------------------------------*/

실제 사용 Example

/*-------------------------Ex 1-------------------------*/
URLSession(configuration: .default)
	.dataTaks(with: URL, completionHandler: (Data?, URLResponse?, Error?) -> Void)

// 위 형태에서 엔터 치면 아래 후행 클로저 형태로 변환
URLSeesion(configuration: .default)
	.dataTaks(with: URL(string: "http://주소")!) { d, r, e in
    	// 데이터 처리하는 코드 입력
    }
/*------------------------------------------------------*/



/*-------------------------Ex 2-------------------------*/
Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false, block: (Timer) -> Void)

// 위 형태에서 엔터 치면 아래 후행 클로저 형태로 변환
// 사후적으로 클로저를 정의해서 인풋으로 넣어준다.
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { (timer) in
	print("0.5초 뒤에 출력하기")	// 실질적으로 timer 변수를 이용하진 않네
}
/*------------------------------------------------------*/



/*-------------------------Ex 3-------------------------*/
class ViewController: UIViewCOntroller {

}
let vc = ViewController()

vc.dismiss(animated: true, completion: ( () -> Void)? )

// 후행 클로저 형태
vc.dismiss(animated: true) {
	print("화면을 닫는 것을 완료했습니다")
}

@escaping

  • 원칙적으로 함수의 실행이 종료되면 parameter로 쓰이는 클로저도 제거된다
  • @escaping 키워드는 클로저를 제거하지 않고, 함수에서 탈출시킨다.
    즉, 함수가 종료되어도 클로저가 존재한다
  • 클로저가 함수의 실행흐름(stack frame)을 벗어날 수 있도록 한다
  • @escaping 사용의 경우
    1. 어떤 함수의 내부에 존재하는 클로저(함수)를 외부 변수에 저장
    2. GCD (비동기 코드의 사용
// (1) 클로저를 단순 실행 (non-escaping) =====================
func performEscaping1(closure: () -> ()) {
    print("프린트 시작")
    closure()
}

performEscaping1 {
    print("프린트 중간")
    print("프린트 종료")
}



// (2) 클로저를 외부변수에 저장 (@escaping 필요) =================
var aSavedFunction: () -> () = { print("출력") }		// aSavedFunction에 클로저 저장

aSavedFunction() 			// "출력"

func performEscaping2(closure: @escaping () -> () ) {	// 파라미터가 closure
	aSavedFunction = closure							// 밖에 있는 함수에 파라미터를 할당
    // 내부에서 closure를 실행하고 있지 않고, 외부의 함수에 할당하고 있다.
}

performEscaping2 {
	print("다르게 출력")		// 출력하지 않고, aSavedFunction에 할당만 한다
}

aSavedFunction()			// "다르게 출력"

@autoclosure

  • 일반적인 클로저 형태로 써도 되지만, 번거로울 때 사용
  • 잘 사용하지는 않고, 읽기 위한 문법이다.
  • 기본적으로 non-escaping 특성
// 파라미터 클로저의 파라미터가 없는 경우에만 사용
func someFunction(closure: @autoclosure () -> Bool) {	
	if closure() {
    	print("참입니다.")
    }
    else {
    	print("거짓입니다.")
    }
}

var num = 1

// 그냥 주면, 자동으로 클로저를 만들어준다 (중괄호를 붙여준다)
someFunction(closure: true)
someFunction(closure: num == 1)

클로저의 실제 사용

// 클로저를 만들어서 그 실행한 결과(return)을 변수에 저장한다. <- 뒤에 소괄호 : 함수의 실행
let emailTextField: UITextField = {
        let tf = UITextField()
        tf.placeholder = "Email"
        tf.backgroundColor = UIColor(white: 0, alpha: 0.3)
        tf.borderStyle = .roundedRect
        tf.font = UIFont.systemFont(ofSize: 14)
        tf.translatesAutoresizingMaskIntoConstraints = false
        //view.addSubview(tf)    // 뷰컨트롤러의 view에 접근 못함
        return tf
}()

0개의 댓글