I am trying to build a Publisher/Observer system to easily observe data changes from API and publish through the app regarding controllers.
The point I have come so far is just working for single observing. However today I came across an issue, which prevents an UIViewController
to observe more than one Publisher
.
I am not sharing the whole code just to prevent confusions and problem below is the main reason, I think. If there is a solution for it, then my problem would be solved.
protocol Base {
associatedtype BaseType
}
protocol One: Base where BaseType == String {}
protocol Two: Base where BaseType == Int {}
class BaseClass {}
extension BaseClass: One {
typealias BaseType = String
}
extension BaseClass: Two {}
When I try to extend the BaseClass
to conform Two
, it throws
'Two' requires the types 'BaseClass.BaseType' (aka 'String') and 'Int' be equivalent
There are additional methods in the Base
protocol and they depend on the BaseType
parameter-wise. But as I said before, I do not think that is the issue.
Any suggestions?
UPDATE: More details with an use-case
My base protocols are as follows;
protocol Publishable {
associatedtype Publisher: Service
}
protocol Service {
associatedtype Publishing: Publishable
var data: Publishing? { get set }
var observers: [AnyObserver<Publishing>] { get set }
func publish(_ data: Publishing)
func add(_ observer: AnyObserver<Publishing>)
}
protocol Observer {
associatedtype ObservingType: Publishable
func subscribe(toService service: ObservingType.Publisher)
func received(_ data: ObservingType)
}
Then I needed a solution for adding different types conforms to Observer into same array. Type erasure applied;
struct AnyObserver<Observing: Publishable>: Observer {
private let _subscribe: (Observing.Publisher) -> Void
private let _received: (Observing) -> Void
init<Base: Observer>(_ base: Base) where Observing == Base.ObservingType {
_received = base.received
_subscribe = base.subscribe
}
func subscribe(toService service: Observing.Publisher) {
_subscribe(service)
}
func received(_ data: Observing) {
_received(data)
}
}
Afterwards our use case is here. Lets say we have a AViewController
which needs data about Book
s and Movie
s from API. I did not include the API part because it is an another layer.
struct Book: Codable {
var name: String?
var author: String?
}
struct BookList: Codable {
var data: [Book]?
var status: Int?
}
extension BookList: Publishable {
typealias Publisher = BookListService
}
struct Movie: Codable {
var name: String?
var director: String?
}
struct MovieList: Codable {
var data: [Movie]?
var status: Int?
}
extension MovieList: Publishable {
typealias Publisher = MovieListService
}
Publishable
extends BookList
and MovieList
because they need to carry information about which Service
object can publish them. BookListService
and MovieListService
are declared as follows;
class BookListService: Service {
var data: BookList?
var observers: [AnyObserver<BookList>] = []
func publish(_ data: BookList) {
//publish
}
func add(_ observer: AnyObserver<BookList>) {
observers.append(observer)
}
}
class MovieListService: Service {
var data: MovieList?
var observers: [AnyObserver<MovieList>] = []
func publish(_ data: MovieList) {
//publish
}
func add(_ observer: AnyObserver<MovieList>) {
observers.append(observer)
}
}
And finally Observer
protocols regarding BookList
and MovieList
.
protocol BookListObserver: Observer where ObservingType == BookList {}
protocol MovieListObserver: Observer where ObservingType == MovieList {}
And for our final use-case regards AViewController
:
class AViewController: UIViewController {
let bookListService = BookListService()
let movieListService = MovieListService()
override func viewDidLoad() {
super.viewDidLoad()
subscribe(toService: bookListService)
}
}
extension AViewController: BookListObserver {
func received(_ data: BookList) {
// booklist received
}
func subscribe(toService service: BookListService) {
service.add(AnyObserver(self))
}
}
Until this point there are no kind of an error. However, all after this, if extending AViewController
conforming to MovieListObserver
throws
'MovieListObserver' requires the types 'BookList' and 'MovieList' be equivalent
extension AViewController: MovieListObserver {}
Just let me know, if you need further updates.
UPDATE:
I have found this topic, but could not apply to my situation somehow.