iOS) 비동기 함수를 호출할 때 종료 시점 Dipsatch Group 로 알기

1 minute read

내용

  • 위젯에서 Intent 를 사용하기위한 IntentHandler 에서 default[parameter type](for:) 메서드로 위젯을 추가할 때 기본값을 설정하는 메서드를 다루겠습니다.
  • 🚨 비동기 서버 통신 작업 이후에 결과를 가지고 함수를 리턴하는 메서드를 구현해야 합니다.
  • 그래서 비동기적인 서버통신 작업의 종료 시점 이후에 처리해야 했습니다.
    // 위젯 추가할때 호출. 기본값 설정.
    // ✅ 서버통신 후에 가장 첫번째 값을 기본값으로 리턴.
    // 서버통신 후에 값이 없다면 기본값으로 nil 리턴.
    func defaultMyCard(for intent: MyCardIntent) -> MyCard? {
        var myCard: MyCard?

        // ✅ DispatchGroup 사용.
        let group = DispatchGroup()
        
        DispatchQueue.global().async(group: group) { [weak self] in
            // ✅ 해당 블록이 disaptch group 에 진입함을 나타냄
            group.enter()
            
            self?.cardListFetchWithAPI { [weak self] result in
                switch result {
                case .success(let result):
                    if let result {
                        // ✅ 위젯의 configuration 을 구성
                        myCard = MyCard(identifier: self?.cardItems?[0].cardUUID ?? "", display: self?.cardItems?[0].cardName ?? "")
                        myCard?.userName = self?.cardItems?[0].userName
                        myCard?.cardImage = self?.cardItems?[0].cardImage
                    }
                case .failure(let err):
                    print(err)
                }
                // ✅ dispatch group 내의 블럭이 실행 종료됨을 나타냄
                group.leave()
            }
        }
        
        _ = group.wait(timeout: .now() + 60)
        
        return myCard
    }

제가 원한 결과는 비동기 서버통신 작업이 시작하고 함수를 리턴하는 것이 아닌 서버통신 작업이 끝나기를 기다린 후에 결과를 가지고 MyCard 자료형으로 리턴하는 것입니다.

(completion handler 를 통해서 비동기 서버통신 작업을 동기적으로 실행할 수 있지만, 위의 경우는 defaultMyCard(for:) 메서드에서 리턴값을 원했기 때문에 서버통신 결과를 기다렸다가 동기적으로 리턴해주어야 했습니다.)

이때 원하는 작업의 종료 시점을 알기 위해서 DispatchGroupenter, leave 를 사용하였습니다.

그래서 cardListFetchWithAPI 의 completion handler 에서 configuration 구성 후에 group.leave() 메서드로 작업의 종료를 알리도록 하였습니다.

추가적으로, wait 를 사용하여 60초간 group 의 작업을 기다리고, 서버통신의 결과를 기다리다가 오래걸린다면 nil 을 반환할 수 있도록 구현해보았습니다.

결과

Categories:

Updated: