iOS 응용 (SwiftUI)
[iOS - SwiftUI] 설계 관점에서 클로저를 이해하며 잘 사용하기 (클로저를 잘 사용하는 방법, 위임하기)
jake-kim
2024. 11. 28. 01:52
모두 알고 있는 클로저 의미 돌아보기
- 다른 부분으로 전달할 수 있는 독립적인 코드 블록
{ (매개변수) -> 반환형 in
실행 코드
}
ex) 클로저 예시 - 기능 실행
let sayHello = { (name: String) -> String in
return "Hello, \(name)!"
}
sayHello("Jake") // "Hello, Jake"
ex) 클로저 예시 - 기능 제공
let multiply = { $0 * $1 }
print(multiply(4, 5))
- 이처럼 클로저는 다른 부분으로 전달할 수 있고 그 것을 저장하여 실행을 지연시킬 수 있는데 여러가지 사용처가 존재
설계 관점에서의 클로저
- 설계 관점에서의 클로저의 역할은 해당 기능을 사용하려는 쪽에 위임 하는 행위의 의미를 가지고 있음
- 커스텀 뷰를 만든다고 했을 때, 데이터와 뷰를 주입하면 커스텀 뷰에 정의된 틀대로 뷰가 보이도록 하고 싶은 경우, 클로저를 사용해야함
- 커스터 뷰 만드는 구체적인 방법은 이전 포스팅 글 뷰를 주입 받는 형태의 커스텀 뷰 만드는 방법 참고
struct ContentView: View {
var body: some View {
// 후행 클로저에 뷰를 받도록하여 CustomView를 사용하는 쪽에서 뷰를 정의하는 방법
CustomView(title: "상단 타이틀", items: [1,2,3]) { item in
Text("item: \(item)")
}
}
}
- 이처럼 커스텀 뷰를 만들때도 사용하는 쪽에서 뷰를 주입받아서 그것을 그대로 보여주어야 할때 뷰를 그려주는 역할을 사용하는 쪽에 위임해주어야 하는데 이때 클로저 사용이 가능
- 이 위임하는 것은 책임을 사용하는 쪽에 돌리게 되어 더욱 유연한 코드 작성이 가능하며, 파라미터로 사용하면 위임하는 코드가 붙어 있어서 더욱 직관적으로 업무 위임이 가능
역할을 위임하는 또 다른 방법 - Delegate와 비교하여 closure 보기
- UIKit안에 있는 UITableView역시도 cell을 그려야 할 때, cellForRowAt이라는 델리게이트 함수에서 사용하는 쪽에서 구현한 셀을 리턴하게되어 뷰를 그리는 행위를 사용하는 쪽에 위임하는데, tableView 인스턴스를 생성하는 코드 밖에 위치하여 가독성이 힘든 단점이 존재
ex) UITableView에서 역할을 위임하는 Delegate 방식
class MyViewController: UIViewController {
func viewDidLoad() {
super.viewDidLoad()
let tableView = UITableView()
tableView.dataSource = self
}
}
extension MyViewController: UITableViewDataSource {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
return cell
}
}
- 만약 이것도 closure로 역할을 위임한다면 이렇게도 구현이 가능
- closure를 사용하면 위 코드보다 더욱 간결하고 조금 더 SwiftUI의 핵심인 선언형태의 코드 흐름을 만들 수 있기 때문에 closure를 통해 역할을 위임하는 설계가 중요
let tableView = UITableView(items: items) { indexPath in
tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
}