使用泛型结构与协议

时间:2018-06-12 10:38:35

标签: swift generics swift-protocols

似乎Swift泛型可以正常工作,只要我不尝试以任何实际方式将它们组合在一起。我正在使用Swift 4.1,我想创建一个只包含弱引用的泛型数组。我可以将其定义为WeakList<T>。到目前为止一切顺利。但是:我想使用T的协议。斯威夫特说没有..

import Foundation

protocol Observer: class {
    func stateChanged(sender: SomeClass, newState: Int)
}

struct WeakList<T> where T: AnyObject {
    struct Ptr {
        weak var p: T?
    }
    private var storage: [Ptr] = []
    var aliveObjects: [T] {
        var result: [T] = []
        for ptr in storage {
            if let p = ptr.p {
                result.append(p)
            }
        }
        return result
    }
    mutating func add(_ obj: T) {
        storage.append(Ptr(p: obj))
    }
    // Let's ignore for a moment that this implementation leaks memory badly.
}

class SomeClass {
    var someVar: WeakList<Observer> = WeakList<Observer>()
    // Error: WeakList requires that 'Observer' be a class type

    var thisIsOk: WeakList<NSObject> = WeakList<NSObject>()
}

(这不是我的原始代码,而是一个包含足够详细信息的最小可验证示例,因此没有人可以说“只是从结构中删除AnyObject约束”)

我想我想做的事情是不可能的。或者是吗?当我尝试使用Swift泛型做一些事情的时候,5次中的4次令人沮丧,我后来才知道我想做的事情是不可能的。 (顺便说一句,我可以轻松地在Objective-C中实现相同的功能。)

  • 我尝试将class约束更改为AnyObject约束=&gt;也不起作用。
  • 我尝试将AnyObject约束更改为class约束=&gt;甚至没有编译。
  • 将其更改为protocol Observer where Self: NSObject并不会改变任何内容。 NSObject是类类型,ObserverNSObject。应该遵循Observer是类类型。 “是一种”关系在这里似乎不具有传递性。

1 个答案:

答案 0 :(得分:1)

使用当前实现,您无法从AnyObject继承协议。您可以做的是为您的协议创建一个类型橡皮擦,然后使用它。现在,您的类型橡皮擦可以从AnyObject继承。

这样的事情:

protocol Observer {
    func stateChanged(sender: SomeClass, newState: Int)
}

class AnyObserver: NSObject, Observer {
    private let observer: Observer

    init(observer: Observer) {
        self.observer = observer
    }

    func stateChanged(sender: SomeClass, newState: Int) {
        observer.stateChanged(sender: sender, newState: newState)
    }
}

struct WeakList<T> where T: AnyObject {
    struct Ptr {
        weak var p: T?
    }
    private var storage: [Ptr] = []
    var aliveObjects: [T] {
        var result: [T] = []
        for ptr in storage {
            if let p = ptr.p {
                result.append(p)
            }
        }
        return result
    }
    mutating func add(_ obj: T) {
        storage.append(Ptr(p: obj))
    }
    // Let's ignore for a moment that this implementation leaks memory badly.
}

class SomeClass {
    var someVar: WeakList<AnyObserver> = WeakList<AnyObserver>()

    var thisIsOk: WeakList<NSObject> = WeakList<NSObject>()
}