0

I'm playing with Combine to learn it and improve my reactive programming skills, and I'm trying to create some generic class that convert data to my T type

I have this error, and I don't understand why

Key path value type '[T]' cannot be converted to contextual type 'T'

class Fetcher<T: Codable>: ObservableObject {
    private var task: AnyCancellable?
    @Published var result = [T]()

    init<T: Codable> (type: T.Type) {
    guard let url = URL(string: "https://api.example.com") else { return }
    task = URLSession.shared.dataTaskPublisher(for: url)
        .map{$0.data}
        .decode(type: T.self, decoder: JSONDecoder())
        .receive(on: DispatchQueue.global(qos: .background))
        .replaceError(with: T.self as! T)
        .assign(to: \.result, on: self)
    }
}

enter image description here

Asperi
  • 228,894
  • 20
  • 464
  • 690
swifthing
  • 440
  • 4
  • 11
  • Does the URL give you an array of `T`s or just one `T`? Also, that `replaceError` looks like it will most definitely crash. – Sweeper Nov 26 '21 at 10:23
  • You need to [edit] your question to include all relevant code as text, using proper code formatting - and not as a screenshot -, in the form of a [mcve] in order to make the question on-topic. – Dávid Pásztor Nov 26 '21 at 10:24
  • @DávidPásztor edit done. – swifthing Nov 26 '21 at 10:27
  • @Sweeper The url gives me an array of T's. Why it would crash? – swifthing Nov 26 '21 at 10:28
  • when you'd decode it, you may need to decode it as an array, eg. `.decode(type: [T].self, decoder: JSONDecoder())` rather than a single item – probably the same applies to the `.replaceError(...)` line as well. – holex Nov 26 '21 at 10:39
  • .decode(type: [T].self, decoder: JSONDecoder()) – Noor Ahmed Natali Nov 26 '21 at 10:54
  • Consider that the generic `T` can be both a single object and an array. And you should not suppress errors in a Codable context. – vadian Nov 26 '21 at 11:50

1 Answers1

3

Since the URL gives you an array of Ts, you should decode an array, rather than a single T in the decode call. This line

.decode(type: T.self, decoder: JSONDecoder())

should be:

.decode(type: [T].self, decoder: JSONDecoder())

That replaceError call is going to crash your app, as T.self is not a T (it's a T.Type), and you are force-casting. Since you are receiving an array, a logical choice for a value to replace errors with, is the empty array []:

.replaceError(with: [])

Also, remove your generic parameter on init:

init() {
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • I changed to [T].self, and changed .replaceError(with: []). Now Xcode is saying "Type of expression is ambiguous without more context" in task = ... – swifthing Nov 26 '21 at 10:39
  • 4
    @swifthing I just found it. You have declared two `T`s. Gosh this is really hard to spot. – Sweeper Nov 26 '21 at 10:48