본문 바로가기

Project/MovieClip

🔍 클로저를 저장하는 변수로?

✅ 클로저를 변수 타입으로?

 

📌 1. (() -> Void)? 타입 해석

var onSearchResultsUpdated: (() -> Void)?
  • (() -> Void)?는 "매개변수가 없고, 반환값도 없는 클로저"를 저장하는 옵셔널 변수를 의미함.
  • 해석하면?
    • () → 매개변수가 없음 (입력 X)
    • -> Void → 반환값이 없음 (출력 X)
    • ? → 옵셔널 (값이 nil일 수도 있음)

📌 onSearchResultsUpdated는 "어떤 동작을 실행할 수 있지만, 필요하지 않을 수도 있는" 함수(클로저)를 저장하는 변수

 

📌 2. 사용 예시

✅ ViewModel에서 클로저 실행

class SearchViewModel {
    var onSearchResultsUpdated: (() -> Void)?  // ✅ 클로저 프로퍼티 선언

    private var movies: [Movie] = []

    func search(query: String) {
        // 검색 결과를 가져온 후 데이터 업데이트
        movies = fetchMovies(query: query)

        // ✅ 클로저 실행 → ViewController에게 "데이터가 변경되었어!" 라고 알림
        onSearchResultsUpdated?()
    }
}

 

  • 검색어가 입력되면 search(query:)를 실행
  • 데이터(movies)가 업데이트되면 onSearchResultsUpdated?() 호출
  • 즉, "내 데이터를 사용하고 있는 객체(ViewController)에게 업데이트됐으니까 UI 바꿔줘!" 라고 알리는 역할

 

📌 3. ViewController에서 사용하기

✅ ViewModel의 클로저를 ViewController에 연결

class SearchViewController: UIViewController {
    private var viewModel = SearchViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        bindViewModel()   // ✅ 여기서 클로저를 "저장"하는 역할을 함
    }

    private func bindViewModel() {
        // ✅ 클로저를 설정 (데이터가 변경되었을 때 실행할 동작)
        viewModel.onSearchResultsUpdated = { [weak self] in
            DispatchQueue.main.async {
                self?.updateUI()
            }
        }
    }

    private func updateUI() {
        print("🔄 UI 업데이트!")
    }
    
    func updateSearchResults(for searchController: UISearchController) {
        guard let query = searchController.searchBar.text, !query.isEmpty else { return }
        viewModel.search(query: query)  // ✅ 검색 실행
    }
}

 

 

📌 설명

  1. bindViewModel()에서 viewModel.onSearchResultsUpdated에 클로저를 대입
    • 이 순간에는 onSearchResultsUpdated?()를 실행하는 게 아님.
    • "나중에 실행될 클로저를 저장"하는 역할만 함!
    • 즉, 검색 결과가 업데이트되었을 때 실행할 행동을 미리 정의하는 것.
  2. search() 함수가 실행되면 onSearchResultsUpdated?()가 호출되면서 UI 업데이트 트리거됨

 

📌 실행 순서

1️⃣ viewDidLoad() 실행 → bindViewModel() 실행됨
2️⃣ viewModel.onSearchResultsUpdated에 UI 업데이트를 실행하는 클로저를 저장
3️⃣ 사용자가 검색어를 입력하면 → updateSearchResults(for:)가 호출됨
4️⃣ viewModel.search(query:) 실행
5️⃣ onSearchResultsUpdated?() 실행
6️⃣ ViewController에서 updateUI()가 실행됨! (UI 업데이트)

 

 

📌 4. ?(옵셔널)인 이유

var onSearchResultsUpdated: (() -> Void)?
  • ViewController에서 bindViewModel()을 실행하지 않으면 onSearchResultsUpdated는 nil 상태
  • 클로저를 실행할 때 nil이면 크래시가 발생하기 때문에 안전하게 onSearchResultsUpdated?() 형태로 호출