URLSession.shared.dataTaskPublisher не работает на IOS 13.3

При попытке сделать сетевой запрос выдает сообщение об ошибке

finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled"

Если я использую URLSession.shared.dataTask вместо того URLSession.shared.dataTaskPublisher он будет работать на iOS 13.3.

Вот мой код:

return  URLSession.shared.dataTaskPublisher(for : request).map{ a in
    return a.data
}
.decode(type: MyResponse.self, decoder: JSONDecoder())
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()

Этот код работал на IOS 13.2.3.

3 ответа

У вас есть 2 проблемы: 1. как сказал @matt, ваш издатель живет недостаточно долго. Вы можете сохранитьAnyCancellable как пример var, или то, что мне нравится делать (и кажется, что это лучшая практика сокращения), - это использовать store(in:) к Set<AnyCancellable>чтобы он оставался поблизости и автоматически очищался, когда объект освобождается. 2. Чтобы запустить фактический сетевой запрос, вам необходимоsink или assign Значение.

Итак, собрав их вместе:

var cancellableSet: Set<AnyCancellable> = []

func getMyResponse() {
  URLSession.shared.dataTaskPublisher(for : request).map{ a in
    return a.data
  }
  .decode(type: MyResponse.self, decoder: JSONDecoder())
  .receive(on: DispatchQueue.main)
  .replaceError(with: MyResponse())
  .sink { myResponse in print(myResponse) }
  .store(in: &cancellableSet)
}

Вы не показали достаточно кода, но по симптому становится ясно, в чем проблема: ваши объекты издателя / подписчика живут недостаточно долго. Рискну сказать, что ваш код всегда был неправильным, и то, что он казался успешным, было просто странностью. Убедитесь, что ваш издатель и особенно ваш подписчик сохранены в долгоживущих объектах, таких как свойства экземпляра, чтобы у сетевого взаимодействия было время.

Вот рабочий пример того, как использовать издателя задач данных:

class ViewController: UIViewController {
    let url = URL(string:"https://apeth.com/pep/manny.jpg")!
    lazy var pub = URLSession.shared.dataTaskPublisher(for: url)
        .compactMap {UIImage(data: $0.data)}
        .receive(on: DispatchQueue.main)
    var sub : AnyCancellable?
    override func viewDidLoad() {
        super.viewDidLoad()
        let sub = pub.sink(receiveCompletion: {_ in}, receiveValue: {print($0)})
        self.sub = sub
    }
}

Это печатает <UIImage:0x6000008ba490 anonymous {180, 206}>, что правильно (как вы сами можете убедиться, перейдя по этому URL-адресу).

Я хочу сказать, что если вы не скажете self.sub = sub, вы получите именно ту ошибку, о которой сообщаете: подписчик sub, который является просто локальным, немедленно прекращает свое существование, а сетевая транзакция преждевременно отменяется (с указанной вами ошибкой).

ИЗМЕНИТЬ Я думаю, что этот код был написан до.store(in:)метод существовал; если бы я писал это сегодня, я бы использовал это вместоsubсвойство. Но принцип тот же.

Мне нужно было переместить отменяемый набор "выше" области действия функции, которую выполнял мой подписчик. Это нормально работало в iOS 13.2, когда отменяемый набор имел ту же область действия, что и функция подписчика, но перестал работать в 13.3. DataTaskPublisher отменяется с ошибкой, указанной выше. Имеет смысл, что отменяемый набор должен "выходить из строя" абонента. Ошибка разработчика. Урок выучен.

Другие вопросы по тегам