결합 및 CoreLocation, 2부 - 이벤트 수신 및 처리

In our previous post, Publisher Factory 또는 Publicist를 구축하는 방법에 대해 이야기했습니다. 이 게시물에서는 새로운 Publicist 클래스에서 ObservableObject의 이벤트를 수신하고 처리하는 방법에 대해 설명합니다.
  • Creating Publishers from Delegates
  • 함수 반응형 프로그래밍을 사용하여 값 변환
  • flatMap 및 기본 제공 게시자 이해

  • ObservableObject에서 이벤트 수신 및 처리



    우리ObservableObject는 CoreLocation 게시자의 말을 듣는 동안 SwiftUI를 업데이트하기 위해 몇 가지 작업을 수행해야 합니다. 우선 다음을 수행해야 합니다.
  • CoreLocation Manager 생성
  • CoreLocation 홍보 담당자 만들기
  • 홍보 담당자를 관리자의 대리인으로 연결
  • 승인 상태 및 위치 게시자 만들기

  • 이를 염두에 두고 보면 다음과 같습니다.

    class CoreLocationObject: ObservableObject {
      @Published var authorizationStatus = CLAuthorizationStatus.notDetermined
      @Published var location: CLLocation?
    
      let manager: CLLocationManager
      let publicist: CLLocationManagerCombineDelegate
    
      var cancellables = [AnyCancellable]()
    
      init() {
        let manager = CLLocationManager()
        let publicist = CLLocationManagerPublicist()
    
        manager.delegate = publicist
    
        self.manager = manager
        self.publicist = publicist
    
        let authorizationPublisher = publicist.authorizationPublisher()
        let locationPublisher = publicist.locationPublisher()
        ...
    
    

    다음으로 게시자로부터 이벤트를 수신하고 처리하는 작업을 실제로 처리할 수 있습니다. 먼저 CLAuthorizationStatus를 다루겠습니다.

    Sink 및 Assign으로 이벤트 수신 및 처리



    CLAuthorizationStatus까지 인증 상태가 변경될 때 수행해야 하는 두 가지 작업이 있습니다.
  • CLAuthorizationStatus가 유효한 경우 트리거 위치 업데이트
  • CLAuthorizationStatus을 @Published CLAuthorizationStatus 속성authorizationStatus에 할당

  • 메서드 호출에 싱크 사용



    먼저 해당 업데이트를 시작하는 메서드를 만들어 위치 업데이트 트리거를 처리해 보겠습니다.

    class CoreLocationObject: ObservableObject {
      @Published var authorizationStatus = CLAuthorizationStatus.notDetermined
      @Published var location: CLLocation?
    
      let manager: CLLocationManager
    
    ...
    
      func beginUpdates(_ authorizationStatus: CLAuthorizationStatus) {
        if authorizationStatus == .authorizedAlways || authorizationStatus == .authorizedWhenInUse {
          manager.startUpdatingLocation()
        }
      }
    }
    
    

    우리의 beginUpdate 메서드는 CLAuthorizedStatus에서 오는 대로 Publisher를 받아들입니다. 결과적으로 상태가 위치 업데이트를 허용하는 경우 startUpdatingLocation에서 CLLocationManager를 호출합니다.

    이를 염두에 두고 authorizationPublisher를 beginUpdates 메서드에 연결해 보겠습니다.

    class CoreLocationObject: ObservableObject {
    
      ...
      var cancellables = [AnyCancellable]()
    
      init() {
        let publicist = CLLocationManagerPublicist()
    
        ...
    
        let authorizationPublisher = publicist.authorizationPublisher()
    
        // trigger an update when authorization changes
        authorizationPublisher
          .sink(receiveValue: beginUpdates)
          .store(in: &cancellables)
        ...
    
    

    이 경우 sink를 사용하고 새 메서드에 대한 참조를 전달합니다. sink는 Cancellable를 반환하며 제대로 처리되었는지 확인해야 합니다. 따라서 .store를 사용하여 Cancellable가 cancelables\ Array에 올바르게 저장되었는지 확인합니다.

    이제 권한이 부여되면 위치 업데이트를 올바르게 시작해야 합니다. 다음으로 CLAuthorizationStatus 속성에 @Published를 저장하여 SwiftUI 보기에 표시할 수 있도록 합니다.

    Assign으로 이벤트 수신 및 처리(iOS 13 및 iOS 14)



    UIKit을 사용하는 iOS 개발자로서 가장 먼저 배우는 것 중 하나는 메인 디스패치 큐에서 UI 업데이트를 만드는 것의 중요성입니다. 즉, 이 작업을 수행하지 않으면 잘못된 UI 업데이트가 발생하거나 앱이 충돌할 수도 있습니다. 마찬가지로 SwiftUI에서는 메인 디스패치 큐에서 UI 업데이트를 지정해야 합니다. 따라서 receive를 사용하여 업데이트가 기본DispatchQueue에 있는지 확인할 수 있습니다.

    ...
          authorizationPublisher
            // since this is used in the UI,
            //  it needs to be on the main DispatchQueue
            .receive(on: DispatchQueue.main)
            ...
    
    

    할당하는 한 몇 가지 옵션이 있습니다. sink를 사용하여 게시된 속성에 값을 할당할 수 있습니다.

    ...
          authorizationPublisher
            // since this is used in the UI,
            //  it needs to be on the main DispatchQueue
            .receive(on: DispatchQueue.main)
            .sink(receiveValue: {
              self.authorizationStatus = $0
            })
    ...
    
    

    그러나 assign를 사용하여 이를 단순화할 수 있습니다.

    ...
          authorizationPublisher
            // since this is used in the UI,
            //  it needs to be on the main DispatchQueue
            .receive(on: DispatchQueue.main)
            // store the value in the authorizationStatus property
            .assign(to: &$authorizationStatus)
    ...
    
    

    This new assign available in all the new 2020 OSes (iOS 14, macOS 11, watchOS 7, etc…)을 사용하면 &(in-out 매개변수용) 및 $(게시자용)를 사용하여 게시자에게 직접 값을 할당할 수 있습니다.

    또한 noCancellable가 반환되므로 저장할 필요가 없습니다.

    이벤트 수신 및 처리 시 싱크 대 할당





    올바른 방법을 선택하는 것은 어려울 수 있지만 다음은 몇 가지 지침입니다.
  • 값을 할당하는 것 외에 추가 논리를 수행하는 경우 sink를 사용하십시오.
  • 값만 할당하려면 assign를 사용하십시오.
  • UI(예: UIKit View 또는 SwiftUI View)에서 직접 사용 중인 값을 할당할 때 .receive(on: DispatchQueue.main) 을 사용합니다.
  • sink 또는 2019 version of assign (즉, assign(to:on:) )를 사용할 때 결과 Cancellable를 using .store 으로 저장하십시오.
  • 하나 이상의 AnyCancellable 속성이 있는 경우 Set or Array for storing the Cancellables 사용을 고려하십시오.

  • 다음 블로그 게시물에서는 CLLocation를 더 유용한 것으로 변환할 때 Combine의 고급 함수형 프로그래밍 기술을 다룰 것입니다.

    좋은 웹페이지 즐겨찾기