斯威夫特:我可以有一个从协议继承并对其进行约束的协议吗?

时间:2019-06-14 17:04:39

标签: swift generics protocols swift-protocols

说我有以下协议:

protocol RateableItem {
   var identifier: String { get }  // placeholder. This could be a lot of properties
   var name: String { get set }
   var rating: Int { get set }
}

protocol RateableItemManager {

    /// get some objects matching query criteria
    func objects(matching query: RateableItemQuery) -> [RateableItem]

    /// get a specific object
    func object(withID identifier: String) -> RateableItem?

    /// persists them
    func save(_ object: RateableItem) throws

    /// deletes the objects.
    func delete(_ objects: [RateableItem])

    /// creates a new object.
    func create() -> RateableItem
}

struct RateableItemQuery {
    let searchPredicate: NSPredicate?  // nil means all
    let sortingBlock: ((RateableItem, RateableItem) throws -> Bool)?
    let groupingSpecifier: (() -> String)?
    init(matching predicate: NSPredicate? = nil,
         sort: ((RateableItem, RateableItem) throws -> Bool)? = nil,
         groupBy: (() -> String)? = nil) {

        self.searchPredicate = predicate
        self.sortingBlock = sort
        self.groupingSpecifier = groupBy
    }
}

我现在可以实现这个的具体类型,它返回符合协议的具体类型。返回的具体类型与我的其余代码无关,因为其余的代码只关心它们是否符合协议。这使我能够制作模型的“生产”和“虚拟”版本。

有没有一种方法可以更一般地定义它,例如:

struct Query<T> {
    let searchPredicate: NSPredicate?  // nil means all
    let sortingBlock: ((T, T) throws -> Bool)?
    let groupingSpecifier: (() -> String)?
    init(matching predicate: NSPredicate? = nil,
         sort: ((T, T) throws -> Bool)? = nil,
         groupBy: (() -> String)? = nil) {

        self.searchPredicate = predicate
        self.sortingBlock = sort
        self.groupingSpecifier = groupBy
    }
}

这样

struct RateableItemQuery: Query<RateableItem> {}

protocol ItemManager<T> {

    func objects(matching query: Query<T>) -> [T]

    func object(withID identifier: String) -> T?

    func save(_ object: T) throws

    func delete(_ objects: [T])

    func create() -> T
}

protocol RateableItemManager: ItemManager<RateableItem>

因为我想使用此API范式,但不一定要在“基本协议”级别上进行任何约束,因为我通常只是针对我要使用的各种协议类型重写这些方法签名想合作。

如果我没记错的话,关联类型必须是具体的,使它们的返回类型也很具体,然后我就不能轻易使用协议类型。

对不起,如果我不说“规范”。我希望我能传达我的意图。

难道这就是即将到来的Swift 5.1在不透明类型方面所提供的,返回->一些ProtocolType吗?

1 个答案:

答案 0 :(得分:0)

所以事实证明,不透明类型也不是答案。

我通过为Manager创建抽象基类解决了我的问题,Query和QueryResults是通用结构,并且Manager的具体子类可以采用和返回基于协议的数据类型。

public struct Query<T> {

    var searchPredicate: NSPredicate?
    var sortingBlock: ((T, T) throws -> Bool)?
    var groupingSpecifier: (() -> String)?

    var results: QueryResults<T>?

    init(matching predicate: NSPredicate?,
         sort: ((T, T) throws -> Bool)?,
         groupBy: (() -> String)?) {

    }
}


public struct QueryResults<T> {

    public enum ChangeType: UInt {
        case insert = 1
        case delete
        case move
        case update
    }

    public struct Section<T> {
        var items: [T]
        var title: String?
    }

    public var sections: [Section<T>] = []

    public func object(at indexPath: IndexPath) -> T? {
        return nil
    }
}

public class AnyObjectManager<ObjectType> {

    public enum Error: Swift.Error {
        case abstractImplementationRequiresOverride
    }

    typealias QueryDidChangeObjectBlock = ((
        _ query: Query<ObjectType>,
        _ didChangeObject: ObjectType,
        _ atPath: IndexPath?,
        _ forChangeType: QueryResults<ObjectType>.ChangeType,
        _ newIndexPath: IndexPath?) -> Void)

    typealias QueryDidChangeSectionBlock = ((
        _ query: Query<ObjectType>,
        _ didChangeSection: QueryResults<ObjectType>.Section<ObjectType>,
        _ atSectionIndex: Int,
        _ forChangeType: QueryResults<ObjectType>.ChangeType) -> Void)

    /// get some objects matching query criteria.  nil means return all
    func objects(matching query: Query<ObjectType>?) -> [ObjectType] {
        fatalError("Abstract implementation.  You need to override this method and provide an implementation!")
    }

    /// get a specific object
    func object(withID identifier: String) -> ObjectType? {
        fatalError("Abstract implementation.  You need to override this method and provide an implementation!")
    }

    /// deletes the objects.  Does it commit that to disk?
    func remove(_ objects: [ObjectType]) {
        fatalError("Abstract implementation.  You need to override this method and provide an implementation!")
    }

    /// creates a new object but does not save it.
    func create() -> ObjectType {
        fatalError("Abstract implementation.  You need to override this method and provide an implementation!")
    }

    /// this is basically to mimic the functionality of a fetched results controller...
    func monitorQuery(_ query: Query<ObjectType>,
                      willChangeBlock: ((_ query: Query<ObjectType>) -> Void)?,
                      didChangeObjectBlock: QueryDidChangeObjectBlock?,
                      didChangeSectionBlock: QueryDidChangeSectionBlock?,
                      didFinishChangesBlock:((_ query: Query<ObjectType>) -> Void)?) {
        fatalError("Abstract implementation.  You need to override this method and provide an implementation!")
    }
    /// and this is to stop monitoring that.
    func stopMonitoringQuery() {
        fatalError("Abstract implementation.  You need to override this method and provide an implementation!")
    }

    public func saveChanges() throws {
        fatalError("Abstract implementation.  You need to override this method and provide an implementation!")
    }

    public func discardChanges() throws {
        fatalError("Abstract implementation.  You need to override this method and provide an implementation!")
    }
}