Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to make this publisher extension generic

I have the following extension on a Publisher which allows me to paginate a URL request. I originally used this in a specific use case, where the Output of the publisher was of type CustomType.

extension Publisher where Output == CustomType,
                          Failure == Error {
  func paginate(pageIdPublisher: CurrentValueSubject<String?, Never>) -> AnyPublisher<[User], Never> {
    return self
      .handleEvents(receiveOutput: { response in
        if let maxId = response.pageId {
          pageIdPublisher.send(maxId)
        } else {
          pageIdPublisher.send(completion: .finished)
        }
      })
      .reduce([]) { allUsers, response in
        return response.users + allUsers
      }
      .catch { error in
        Just([])
      }
      .eraseToAnyPublisher()
  }
}

struct CustomType: Codable {
  let users: [User]
  let pageId: String?
}

This is called like this:

func loadItem() async throws -> [String] {
  let pageIdPublisher = CurrentValueSubject<String?, Never>(nil)

  return try await pageIdPublisher
    .flatMap { pageId in
      urlSession
        .publisher(
          for: .item(pageId: pageId),
          receiveOn: queue
        )
    }
    .paginate(pageIdPublisher: pageIdPublisher) // <- This part
    .singleOutput()
}

However, I now want to make it generic so that it can be used on any Output type, so long as it has a pageId and some kind of array.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I tried using a protocol Pageable like this:

protocol Pageable {
  associatedtype T

  var pageId: String? {get}
  var items: [T] {get}
}

But I can’t use that with the extension because Output can’t have be used with a protocol that contains an associatedType.

Is this possible?

>Solution :

If you constrained the Output type with : to your Pageable protocol, and used Output.T for the returned publisher’s output type, the paginate method should compile:

extension Publisher where Output: Pageable,
                          Failure == Error {
  func paginate(pageIdPublisher: CurrentValueSubject<String?, Never>) -> AnyPublisher<[Output.T], Never> {
   return self
     .handleEvents(receiveOutput: { response in
       if let maxId = response.pageId {
         pageIdPublisher.send(maxId)
       } else {
         pageIdPublisher.send(completion: .finished)
       }
     })
     .reduce([]) { allItems, response in
       return response.items + allItems
     }
     .catch { error in
       Just([])
     }
     .eraseToAnyPublisher()
  }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading