본문 바로가기

Swift/문법 정리

클로저(Closure)를 알아보자

사실상 이번에 앱센터에서 팀 프로젝트를 진행하면서 가장 유용하게 사용했던게 클로저인 것 같다.

 

그동안 클로저를 공부하고 도대체 어디다가 써먹는거지하고 그냥 클로저말고 함수를 사용하면 된다고 생각했지만

이번에 네트워킹 작업과 view들간의 이동에서 원하는 위치에서 함수를 실행해야하는 경우에 정말 유용하게 사용했다.

특히 completion Handlers를 유용하게 사용해서 오늘 정리하고자 한다.

 

클로저에 대한 설명은 swift 공식 문서에 잘 나와있으니깐 해당 문서를 참고하길...

https://devxoul.gitbooks.io/ios-with-swift-in-40-hours/content/Chapter-3/functions-and-closures.html

 

함수와 클로저 (Closure) · 40시간만에 Swift로 iOS 앱 만들기

 

devxoul.gitbooks.io

https://jusung.gitbook.io/the-swift-language-guide/language-guide/07-closures

 

 

해당 동영상의 로직은 첫 번째 뷰컨(SaveListViewController)에서 두 번째 뷰컨(AlertViewController)을 present하고 사용자에게 응답을 받아서 첫 번째 뷰컨의 indexPath에 맞는 cell을 삭제하는 것이다.

 

그래서 쉽게 구현하기 위해 클로저를 사용해주었다.

 

먼저 첫 번째 뷰컨은 collectionView로 화면을 구성했다.

그래서 collectionView의 커스텀 Cell을 정의한 파일에 이런식으로 해당 클로저를 정의하고 사용했다.

 

1. SaveListCell파일에 사용된 예시

    var bookMarkClosure: (() -> Void)?
    @objc func bookMarkButtonClicked(_ sender: UIGestureRecognizer) {
        if let bookMarkClosure = bookMarkClosure {
            bookMarkClosure()
        }
    }

 

즉, cell에 있는 북마크 버튼이 클릭되면 bookMarkButtonClicked()함수가 실행되는 것이고

실행되는 내용인 bookMarkClosure()는 나중에 정의해주겠다는 얘기이다.

 

이유는 우리는 SaveListCell에서 bookMarkButtonClicked()함수가 실행되는걸 원하는게 아니라 

SaveListViewController에서 북마큰 버튼이 눌려서 응답받은 결과로 해당 indexPath의 cell을 삭제를 하거나 그대로 놧두거나 해야하기 때문이다.

 

2. AlertViewController에 사용된 예시

    var alertIsSaveClosure: (() -> Void)?
    func alertIsSave() {
        if let alertIsSaveClosure = alertIsSaveClosure {
            alertIsSaveClosure()
        }
    }

해당 alertIsSave() 함수는 사용자가 확인을 눌렀을 때 실행되는 함수이며,

사용자에게 삭제 여부를 묻는 AletViewController에 사용된 예시이다.

 

결국엔 사용자에게 삭제 여부를 받고 그 행동은 SaveListViewController

즉, 첫 번째 뷰컨에서 실행되야하기 때문에 함수가 실행되는 부분은 클로저로 선언해주고 해당 내용은 첫 번째 뷰컨에서 정의해주는 것이다.

 

3. SaveListViewController에 사용된 예시

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SaveListCell.identifier, for: indexPath) as? SaveListCell else { return UICollectionViewCell() }
        
        cell.setUI(event: saveListViewModel.eventAtIndex(index: indexPath.item))
        
        cell.bookMarkClosure = {
    
            let alertViewController = AlertViewController()
            alertViewController.alert = .save
            alertViewController.modalPresentationStyle = .overFullScreen
            alertViewController.modalTransitionStyle = .crossDissolve
            self.present(alertViewController, animated: true)
            
            alertViewController.alertIsSaveClosure = {
                
                self.saveListViewModel.deleteLike(index: indexPath.item) {
                    self.setAPI()
                    self.dismiss(animated: true)
                }
            }
            
        }
        return cell
    }

결국에는 SaveListViewController - collectionView의 cellForItemAt메서드에 그동안 선언만 해주고 정의해주지 않은 내용들을 정의해주는 것이다.

 

먼저 cell의 북마크 버튼이 클릭되면 SaveListCell에 선언된 bookMarkClosure를 정의해주는 것이다.

해당 클로저는 북마크 버튼을 눌렀을 때 실행되는 클로저이며 alertViewController가 present되게 된다.

즉, 해당 cell의 indexPath를 가지고 첫 번째 뷰컨에서 두 번째 뷰컨으로 넘어가는 것이다.

 

그다음에는 alertViewController에 선언해주었던 alertIsSaveClosure를 정의해주는 것이다.

즉, alerIsSaveClousre는 사용자가 확인을 눌렀을 때 실행되는 클로저이고 사용자가 확인을 누르게 되면

뷰모델에 선언했던 deleteLike 메서드가 실행되면서 해당 indexPath.item의 cell이 삭제가되어 서버로 보내지게 되고

다시 setAPI()를 통해서 서버로부터 저장 목록 데이터를 가져와 CollectionView를 reload해준다.

그 뒤에는 두 번째 뷰컨을 dismiss해주면 된다.

 

정리하자면 결국에 클로저를 사용한 이유는 함수가 실행되는 위치를 조절해주기 위해서다.

 

사실상 해당 저장 목록화면의 cell을 삭제하기 위한 작업은 SaveListViewController 첫 번째 뷰컨에서 실행되어야하지만

사용자에게 삭제여부를 묻는 작업이 AlertViewController 두 번째 뷰컨에서 하게 된다.

두 번째 뷰컨은 해당 cell의 indexPath에 대한 정보가 없기 때문에 삭제 처리를 해주지 못하게된다.

그래서 !!!! 첫 번째 뷰컨에서 삭제 여부를 받아와 그에 맞는 함수를 실행하고자 클로저를 사용했던 것이다!

 

즉 completion closure는 사용자가 원하는 위치에서 원하는 함수를 사용하기 위해 사용한다!

 

 

 

'Swift > 문법 정리' 카테고리의 다른 글

Map 함수  (0) 2022.05.09
타입 캐스팅(업캐스팅 & 다운캐스팅)  (0) 2022.04.04
옵셔널 타입  (0) 2022.04.03