Как мне вернуть результат моего вызова выборки с помощью combine?

#swift #combine

#swift #объединить

Вопрос:

Я новичок в combine и изо всех сил пытаюсь понять, как я могу вернуть результат моих выводов выборки.

Я могу установить результат как @Published , но я хочу просто иметь возможность вызывать метод выборки и ожидать результата или ошибки.

 class PinService: NSObject, ObservableObject {
    private var session: Session
    private var subscriptions = Set<AnyCancellable>()
    
    init(session: Session) {
        self.session = session
        super.init()
    }
    
    func fetchPins (categories: Set<CategoryModel>, coordinates: CLLocationCoordinate2D)  {
        _fetchPins(categories: categories, coordinates: coordinates)
            .sink(receiveCompletion: { completion in
                switch completion {
                case .failure:
                    print("fetchPins() error")
                case .finished:
                    print("fetchPins() complete")
                }
            }, receiveValue: { pins in
                /*
                    What to do here?
                 
                    I can add a @Published var pins: [Pin], and do
                    self.pins = pins
                 
                    But if I want to be able to return the value or the error, how can I do that?
                 */
            })
            .store(in: amp;self.subscriptions)
    }
    

    private func _fetchPins(categories: Set<CategoryModel>, coordinates: CLLocationCoordinate2D) -> Future<[Pin], Error> {
        return Future<[Pin], Error> { promise in
            let categoryIds = categories.map { return $0.id }.joined(separator: ",")
            
            let radius = 15 //miles
            
            self.session.request(baseUrl   "/api/v1/pinsRadius?latitude=(coordinates.latitude)amp;longitude=(coordinates.longitude)amp;radius=(radius)amp;categories=(categoryIds)")
                .responseDecodable(of: [Pin].self) { (response: DataResponse) in
                    switch response.result {
                    case .success(let pins):
                        promise(.success((pins)))
                    case .failure(let error):
                        promise(.failure(error))
                    }
            }
        }
    }
}
  

Извините, если это глупый вопрос, спасибо.

Ответ №1:

Одним из решений является использование обработчика завершения в вашей функции и вызов его из receiveValue

 func fetchPins (categories: Set<CategoryModel>, 
                coordinates: CLLocationCoordinate2D, 
                completion: @escaping (Result<[Pin], Error>) -> Void))  {
    _fetchPins(categories: categories, coordinates: coordinates)
        .sink(receiveCompletion: { completion in
            switch completion {
            case .failure(let error):
                completion(.failure(error))
                print("fetchPins() error")
            case .finished:
                print("fetchPins() complete")
            }
        }, receiveValue: { pins in
            completion(.success(pins))
        })
        .store(in: amp;self.subscriptions)
}
  

Тогда ваш вызов fetchPins будет выглядеть примерно так

 fetchPins(categories: someValue, coordinates: someOtherValue) { pins in
    //do stuff with pins here
}
  

Комментарии:

1. Спасибо! Как я могу также отправить ошибку? У меня нет ошибки в блоке receiveValue.

2. Вы можете изменить тип параметра для обработчика завершения с [Instrument] на Result<[Instrument], Error>, а затем вызвать его с помощью .success или .failure

3. Какова цель .store(in: amp;self.subscriptions) , если контакты уже сохранены в завершении: completion(.success(pins) ?

4. Сохраняется подписка

5. Хорошо, я понял. Так что это нужно только в том случае, если вы также хотите сохранить подписку помимо контактов (в этом примере) ?.