본문 바로가기

UIKIT

viewModel.$user에서 user 앞에 $를 붙이는 이유

https://explorer89.tistory.com/295

 

ViewModel을 사용하는 목적

https://explorer89.tistory.com/294 ViewModelhttps://explorer89.tistory.com/82 ObservableObject와 @Published개체가 변경되기 전에 내보내는 게시자가 있는 개체 형식이다.?  @Published와 ObservableObject는 스위프트의 Combine

explorer89.tistory.com

 

private func bindViews() {
    emailTextField.addTarget(self, action: #selector(didChangeEmailField), for: .editingChanged)
    passwordTextField.addTarget(self, action: #selector(didChangePasswordField), for: .editingChanged)
    viewModel.$isRegistrationFormValid.sink { [weak self] validationState in
        self?.registerButton.isEnabled = validationState
    }
    .store(in: &subscription)

    viewModel.$user.sink { [weak self] user in
        dump("user info: \(user)")
    }
    .store(in: &subscription)
}

 

viewModel.$user에서 user 앞에 $를 붙이는 이유

  • $user는 @Published 프로퍼티의 Publisher를 나타냅니다.
    • @Published 프로퍼티(user)는 상태를 저장하고, 값이 변경될 때 이벤트를 방출합니다.
    • 이 방출되는 이벤트를 사용하려면 user에 접근하는 것이 아니라, Publisher 형태로 접근해야 합니다.
    • Publisher로 접근하려면 @Published 프로퍼티 앞에 $를 붙여야 합니다. 
@Published var user: User?  // 사용자 상태를 저장하는 프로퍼티
viewModel.$user             // 이 프로퍼티가 변경될 때 이벤트를 방출하는 Publisher

 

 

bindViews 함수에 대한 전체 설명

bindViews는 ViewController의 UI 요소와 ViewModel을 데이터 바인딩하기 위한 함수입니다.

이 함수의 역할

  • 텍스트 필드의 변경 이벤트를 감지
    • 이메일 입력 필드(emailTextField)와 비밀번호 입력 필드(passwordTextField)에 대해, 텍스트가 변경될 때 실행될 메서드를 설정합니다.
    • addTarget(_:action:for:) 메서드를 사용하여 각각 didChangeEmailField와 didChangePasswordField를 호출하도록 연결합니다. 
emailTextField.addTarget(self, action: #selector(didChangeEmailField), for: .editingChanged)
passwordTextField.addTarget(self, action: #selector(didChangePasswordField), for: .editingChanged)

 

  • 회원가입 버튼 활성화 상태 관리
    • viewModel.$isRegistrationFormValid를 구독하여, 이메일과 비밀번호가 올바르게 입력되었는지 상태를 확인합니다.
    • sink 클로저 내부에서 이 상태(validationState)에 따라 회원가입 버튼(registerButton)의 활성화 여부를 설정합니다.
viewModel.$isRegistrationFormValid.sink { [weak self] validationState in
    self?.registerButton.isEnabled = validationState
}
.store(in: &subscription)

 

  • 사용자 정보 확인
    • 회원가입 요청이 성공하면 viewModel.$user의 값이 업데이트됩니다.
    • 이를 감지하여, 변경된 user 객체의 정보를 dump를 통해 콘솔에 출력하거나 다른 동작을 처리할 수 있습니다.
viewModel.$user.sink { [weak self] user in
    dump("user info: \(user)")
}
.store(in: &subscription)

 

함수의 동작 순서

  1. 사용자가 이메일 또는 비밀번호를 입력하면, 각각의 @objc 메서드(didChangeEmailField, didChangePasswordField)가 호출됩니다.
    • 해당 메서드는 ViewModel의 email 또는 password 값을 업데이트하고, validateRegistrationForm()을 호출하여 입력 값의 유효성을 검증합니다.
  2. validateRegistrationForm() 결과에 따라 isRegistrationFormValid 값이 업데이트됩니다.
    • viewModel.$isRegistrationFormValid가 변경되면 sink 클로저가 실행되어 버튼의 활성화 상태를 업데이트합니다.
  3. 회원가입 요청(viewModel.createUser())이 성공하면, viewModel.$user가 업데이트됩니다.
    • 이 변경을 감지한 sink가 실행되어 사용자 정보를 출력하거나 후속 동작을 수행합니다.

 

 

.sinkCombine 프레임워크에서 Publisher가 방출하는 값을 구독(subscribe)하고 처리하기 위한 메서드입니다. Publisher가 새로운 값을 방출하거나, 완료 또는 오류 이벤트가 발생했을 때, 해당 이벤트를 처리하는 클로저를 실행합니다.

 

1. .sink의 역할

Publisher의 이벤트를 구독

  • .sink는 Combine에서 Publisher가 제공하는 데이터 스트림(이벤트)을 구독하여 처리합니다.
  • 구독하는 동안 발생할 수 있는 3가지 이벤트를 처리할 수 있습니다:
    1. 값 방출 이벤트 (value): Publisher가 데이터를 방출할 때 실행.
    2. 완료 이벤트 (completion): Publisher가 더 이상 데이터를 방출하지 않고 완료되었을 때 실행.
    3. 오류 이벤트 (failure): Publisher가 에러를 방출하면 실행.

 

2. .sink의 기본 문법

publisher.sink(receiveCompletion: { completion in
    // 완료 이벤트 처리
    switch completion {
    case .finished:
        print("Publisher finished")
    case .failure(let error):
        print("Publisher failed with error: \(error)")
    }
}, receiveValue: { value in
    // 방출된 값 처리
    print("Received value: \(value)")
})

 

  • receiveCompletion 클로저:
    • Publisher가 완료(.finished) 또는 실패(.failure)했을 때 호출.
    • 생략 가능.
  • receiveValue 클로저:
    • Publisher가 값을 방출할 때 호출.
    • 반드시 정의해야 함.

 

요약

.sink는 Combine에서 데이터를 처리하기 위해 사용하는 주요 구독 메서드로, 다음 역할을 합니다:

  1. Publisher의 값 방출 이벤트 처리: 데이터 스트림에서 값을 받아 원하는 작업을 수행.
  2. 완료 또는 오류 이벤트 처리: Publisher가 종료되었을 때의 동작을 정의.
  3. 구독 관리: 반환된 AnyCancellable로 메모리 누수를 방지.

'UIKIT' 카테고리의 다른 글

eraseToAnyPublisher(), Set<AnyCancellable>  (0) 2025.01.08
Combine을 활용한 함수  (0) 2025.01.08
ViewModel을 사용하는 목적  (0) 2025.01.08
UITabBarAppearance  (0) 2025.01.05
UICollectionReusableView와 UIView의 차이 + headerSection  (0) 2025.01.05