2023년 1월 1일
08:00 AM
Buffering ...

최근 글 👑

[Swift-Study] 베이직반 2회차 - 1회차 복습, Closure 활용 VC 간 통신

2024. 4. 11. 20:54ㆍIOS/Swift-Study
SMALL

베이직 반 1회차 복습

클로저는 무엇인가요? (생각해보기)

더보기

동작을 저장할 수 있는

변수/상수에 저장 가능

파라미터로 전달 가능

함수에서 반환 가능

타입을 가짐 = Function Type

func sayHello(name: String) { 

}

sayHello 의 함수 타입은 어떻게 되나요? (실습해보기)

힌트 = 앞쪽은 파라미터, 뒤에는 반환타입

더보기

(String) -> ()

(String) -> Void

이런식으로 함수 타입이 표현 됩니다.

함수는 Closure 의 한 종류(Named closure) 라는 것.

 

add 라는 변수에 두 개의 숫자를 받고,

두 개의 숫자를 더한 결과를 반환하는 클로저를 저장해보기

더보기

먼저,

add 라는 변수를 만들어주고,

var add

 

여기에 클로저를 저장을 할껀데 클로저의 형태는

중괄호로 감싸져 있는 형태이죠?

var add = {

}

이런식으로 중괄호로 변수 add를 감싸줍니다.

 

이제 여기서 2개의 숫자 즉, 2개의 파라미터를 받아야 하는데

파라미터를 받을 때에는 소괄호 안에 감싸주어야 했습니다.

var add = { (first: Int, second: Int)

}

첫번째 파라미터인 first와 두번째 파라미터인 second를 받아서,

var add = { (first: Int, second: Int) -> 

}

반환타입은 화살표(->)뒤로 표현 했고,

 

var add = { (first: Int, second: Int) -> Int in

}

Int를 더한 값을 반환 할 것이다 라고 표현해주는데,

여기서 하나 더 봐야 할 부분은 바디부분에서

파라미터와 반환 되는 부분과 구분을 하기 위해서 in을 써주어야 합니다.

 

var add = { (first: Int, second: Int) -> Int in
	return first + second
}

첫번째 파라미터인 first와 두번째 파라미터인 second를 더한 값이 필요하기 때문에

return 으로 첫번째 파라미터 + 두번째 파라미터를 해줍니다.


[돌발퀴즈]

add 클로저의 Function Type 은? (실습해보기)

(답은 맨 마지막 줄에 써놓았습니다.)

var add = { (first: Int, second: Int) -> Int in
	return first + second
}

add()

add 함수를 호출하면 실행이 될까요? (실습해보기)

(답은 맨 마지막 줄에 써놓았습니다.)


고차함수 직접 구현

고차함수는 함수를 파라미터로 받는 함수입니다.

add 함수를 업그레드시켜보자

func add(first: Int, second: Int) {
	let result = first + second
	// result 를 가지고 어쩌고 저쩌고 하는 함수
	// ...
}

 

 

completionHandler 파라미터를 추가 해보도록 합시다.

func add(first: Int, second: Int, completionHandler: (Int) -> Void) {
	let result = first + second
}

completionHandler 는 계산결과를 가지고 할 수 있는 행동을 정의한다는 의도로 작성해 주는데,

completionHandler는 함수타입을 Int를 파라미터로 넣고,

 아무것도 반환하지 않을 것이다 라는 의미로 Void 를 해주는 함수타입으로 정의해줍니다.

 

조금 더 알기 쉽게 정리 해 보겠습니다.

func add(first: Int,
	second: Int, 
        completionHandler: (Int) -> Void) {

	let result = first + second
}

 

첫번째 파라미터도 Int 타입이고, 두번째 파라미터도 Int 타입이죠?

세번째 파라미터는 무슨타입이죠? (생각해보기)

더보기

함수타입 입니다.

이제 함수 내부에서 파라미터를 사용할 수 있는

틀이 완성 되었다고 볼 수 있습니다.

그 말은 즉, completionHandler를 사용할 수 있다는 뜻이고,

completionHandler는 파라미터를 받을 수 있고

또 얘는 클로저이니까 아래와 비슷하게 호출을 해주어야겠죠?

func add(first: Int,
	second: Int, 
        completionHandler: (Int) -> Void) {

	let result = first + second
    
    completionHandler(result)
}

이런식으로 첫번째 파라미터와 두번째 파라미터를 더한 값을

completionHandler 파라미터로 받은 함수 타입에 넣은 상태가 됩니다.

이제 호출을 한번 해봅시다.

func add(first: Int, second: Int, completionHandler: (Int) -> Void) {

	let result = first + second
	
	completionHandler(result) // result 값을 전달하며 호출됨
}

	// completionHandler 에 우리가 할 동작을 전달
	// 호출하면서 전달한 클로져가 add 함수 내부에서 호출됨
	add(first: 1,
	second: 2,
	completionHandler: { 
    	
})

completionHandler 에는 클로저를 넣어 주어야 하는데,

completionHandler 의 타입은 (Int) -> Void) 이죠?

func add(first: Int, second: Int, completionHandler: (Int) -> Void) {

	let result = first + second
	
	completionHandler(result) // result 값을 전달하며 호출됨
}

	// completionHandler 에 우리가 할 동작을 전달
	// 호출하면서 전달한 클로져가 add 함수 내부에서 호출됨
	add(first: 1,
	second: 2,
	completionHandler: { (number: Int) -> Void in

})

이런식으로 클로저를 전달 했다고 보시면 됩니다.

그렇다면, 이제 number를 가지고 무언가를 해줘야 하는데,

func add(first: Int, second: Int, completionHandler: (Int) -> Void) {

	let result = first + second
	
	completionHandler(result) // result 값을 전달하며 호출됨
}

	// completionHandler 에 우리가 할 동작을 전달
	// 호출하면서 전달한 클로져가 add 함수 내부에서 호출됨
	add(first: 1,
	second: 2,
	completionHandler: { (number: Int) -> Void in
	print("계산 결과는 \(number)"입니다!)
})

이런식으로 동작을 정의해 줄 수 있습니다.

즉, "number가 호출되면 난 이걸가지고 print를 호출 할 것이다." 라는 것 입니다.

그렇다면 여기까지 작성되었을때 결과는 어떤 결과가 나올지 예상해봅시다.

더보기

계산 결과는 3 입니다!

클로져 파라미터 이름은 생략이 가능합니다.

func add(first: Int, second: Int, completionHandler: (Int) -> Void) {

	let result = first + second
	
	completionHandler(result)
}

	add(first: 1,
	second: 2,
	completionHandler: {
	print("결과는 \($0)"입니다!)
})

생략을 하게 될 경우 달러($)를 사용해서 파라미터를 불러올 수 있습니다.

$0은 첫번째 파라미터를 뜻 합니다.

 

trailing closure 생략

add(first: 1, second: 2) { number in
    print("결과는 \(number)"입니다!)
}

Closure 활용 VC 간 통신

예시로 A, B 2개의 화면이 있고,

 

A → B 로 이동하는 플로우를 가지고 있는데,

B 화면에는 +/- 스테퍼 기능 있고,

B 화면에서 증가시키면 A 화면의 숫자가 반영되는것을 말합니다.

 

단순히 UIKit에서 끌어다 만들기만 하면 되는게 아니죠.

코드와 함께 연결을 시켜주어야 합니다.

이런식으로 레이블을 연결해주고,

동작을 정의를 해주어야겠죠?

이런식으로 동작을 정의해 주었는데, 

let number = Int("1")을 임의로 해놓았는데,

let number = Int(numberStr)로 바꿔야

+ 버튼을 누를 때마다 계속 숫자가 늘어납니다.

 

이제 필요한건 + 버튼을 눌렀을 때 호출되는 값이 필요하죠?

두번째 화면 컨트롤러에서 버튼을 액션으로 연결해주고,

빌드를 해보면 됩니다.


CompletionHandler API

dataTask

https://developer.apple.com/documentation/foundation/urlsession/1410330-datatask

 

dataTask(with:completionHandler:) | Apple Developer Documentation

Creates a task that retrieves the contents of the specified URL, then calls a handler upon completion.

developer.apple.com

 

더보기

돌발퀴즈 정답 :  (Int, Int) -> Int

파라미터 두개를 받고 화살표로 반환값 구분해 주고, 반환타입 Int

var add = { (first: Int, second: Int) -> Int in
	return first + second
}
let result = add(1, 2) // 3
print(result)

+  위 코드를 호출 하기 위해서는 당연히 값이 필요하기 때문에 Int 정수형인 값을 두개 입력 해줍니다.

    또한 Swift에서 클로저를 변수에 할당할 때, 클로저의 타입을 명시하거나 Swift가 자동으로 추론하도록 해야하기 때문에

    클로저를 호출할 때는 함수와 마찬가지로 이름 뒤에 괄호를 붙여야 합니다.

print(add(1, 2))

+ 더 간단하게 이런식으로도 호출은 가능하니다만, 일반적으로는 위에서 let result로 클로저를 선언하고 호출합니다.

728x90