Swift 符合多个协议继承自具有关联类型的相同协议

时间:2021-02-11 12:28:33

标签: swift swift-protocols protocol-oriented

我正在尝试构建一个发布者/观察者系统,以便轻松观察来自 API 的数据更改并通过应用程序发布有关控制器的信息。

我到目前为止的观点只是为单次观察工作。但是今天我遇到了一个问题,该问题阻止 UIViewController 观察多个 Publisher

我不是为了防止混淆而分享整个代码,我认为下面的问题是主要原因。如果有解决方案,那么我的问题就解决了。

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 {}

当我尝试扩展 BaseClass 以符合 Two 时,它抛出

'Two' requires the types 'BaseClass.BaseType' (aka 'String') and 'Int' be equivalent

Base 协议中有其他方法,它们依赖于 BaseType 参数。但正如我之前所说,我不认为这是问题所在。

有什么建议吗?

更新:用例的更多细节

我的基本协议如下;

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)
}

然后我需要一个解决方案,将符合 Observer 的不同类型添加到同一个数组中。应用类型擦除;

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)
    }
}

之后我们的用例就在这里。假设我们有一个 AViewController,它需要来自 API 的 BookMovie 的数据。我没有包括 API 部分,因为它是另一层。

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 扩展了 BookListMovieList,因为它们需要携带有关哪个 Service 对象可以发布它们的信息。 BookListServiceMovieListService 声明如下;

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)
    }
}

最后是关于 ObserverBookListMovieList 协议。

protocol BookListObserver: Observer where ObservingType == BookList {}
protocol MovieListObserver: Observer where ObservingType == MovieList {}

对于我们最后的用例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))
    }
    
}

到目前为止,没有任何错误。然而,在此之后,如果扩展 AViewController 符合 MovieListObserver 抛出 'MovieListObserver' requires the types 'BookList' and 'MovieList' be equivalent

extension AViewController: MovieListObserver {}

如果您需要进一步的更新,请告诉我。

更新:

我找到了 this topic,但无法以某种方式适用于我的情况。

0 个答案:

没有答案