0

Environment:
Xcode Version 11.3 (11C29)
Apple Swift version 5.1.3

Scenario: Combine Neophyte attempting to learn URLSession.shared.dataTaskPublisher

Details: I made a simple app to access weather data (any data) via two means:
1) Standard and
2) via Publisher

1) Here's the result: Weather data via Standard paradigm:

Sample(coord: DataTaskPublisher.Coord(lon: -0.13, lat: 51.51), weather: [DataTaskPublisher.Weather(id: 300, main: "Drizzle", description: "light intensity drizzle")], base: "stations", main: DataTaskPublisher.Main(temp: 280.32, pressure: 1012, humidity: 81, tempMin: 279.15, tempMax: 281.15), visibility: 10000, wind: DataTaskPublisher.Wind(speed: 4.1, deg: 80), clouds: DataTaskPublisher.Clouds(all: 90), dt: 1485789600.0, id: 2643743, name: "London")

2) However the following error result is what I get via Combine's Publisher paradigm:

2019-12-27 12:48:31.019760-0800 DataTaskPublisher[36228:13390491] Task <8770DDAB-78BC-48D1-BA6C-F5941742E4FA>.<2> finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22, NSLocalizedDescription=cancelled, NSErrorFailingURLKey=https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22}


Here are the two codes (Standard, following with Publish):
import UIKit

let weatherURL = "https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22"
let calculationID = "51f82d8e-64ed-4d80-808c-b1c29c780d28"
let calculatorBase = "https://calculator-frontend-challenge.herokuapp.com/Calculations"

enum EndPoint {
    case weather
    case calc

    func path() -> URL? {
        switch self {
        case .weather:
            return URL(string: weatherURL)
        default:
            return nil
        }
    }
}
   func doStandard() {
        let url = EndPoint.weather.path()

        let task = URLSession.shared.dataTask(with: url!) { (data: Data?, _: URLResponse?, error: Error?) -> Void in

            do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                let result = try decoder.decode(Sample.self, from: data!)
                print(result)
            } catch let error as NSError {
                print(error)
            }
        }
        task.resume()
    }

    // ---------------------------------------------------------------------------

    func doPublish() {
        let url = EndPoint.weather.path()
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        let remoteDataPublisher = URLSession.shared.dataTaskPublisher(for: url!)
            // the dataTaskPublisher output combination is (data: Data, response: URLResponse)
            .map { $0.data }
            .decode(type: Sample.self, decoder: decoder)

        let _ = remoteDataPublisher
            .sink(receiveCompletion: { completion in
                print(".sink() received the completion", String(describing: completion))
                switch completion {
                case .finished:
                    break
                case .failure(let anError):
                    print("received error: ", anError)
                }
            }, receiveValue: { someValue in
                print(".sink() received \(someValue)")
            })
    }
}

Note: the 'Publish' version code is from a template in a tutorial. It had worked with a different URL.

What am I missing?
... or doing wrong?


Here's the data object for the JSON Decoder:

struct Coord: Codable {
    let lon: Double
    let lat: Double
}

struct Weather: Codable {
    let id: Int
    let main: String
    let description: String
}

struct Wind: Codable {
    let speed: Double
    let deg: Int
}

struct Main: Codable {
    let temp: Double
    let pressure: Int
    let humidity: Int
    let tempMin: Double
    let tempMax: Double
}

struct Sys: Codable {
    let type: Int
    let id: Int
    let message: Double
    let country: String
    let sunrise: Int
    let sunset: Int
}

struct Clouds: Codable {
    let all: Int
}

struct Sample: Codable {
    let coord: Coord
    let weather: [Weather]
    let base: String
    let main: Main
    let visibility: Int
    let wind: Wind
    let clouds: Clouds
    let dt: Double
//    let sys: Sys
    let id: Int
    let name: String
//    let cod: Int
}
Frederick C. Lee
  • 9,019
  • 17
  • 64
  • 105
  • 1
    The problem is that you are throwing away your `.sink` subscriber immediately, so the whole thing is cancelled before it has a chance to do any networking. You need to call `store(in:)` on the `.sink` to preserve it, typically in a `Set` instance property. The linked question-and-answers demonstrates. – matt Dec 27 '19 at 21:36
  • Thanks. Followed references and works now. – Frederick C. Lee Dec 28 '19 at 22:11

0 Answers0