以下代码给我一个编译错误
“ WeakReference”要求“ ServiceDelegate”为类类型
protocol ServiceDelegate: AnyObject {
func doIt()
}
class SomeClass() {
// compile error occurs in this line
private var observers = [WeakReference<ServiceDelegate>]()
}
弱引用代码:
final class WeakReference<T: AnyObject> {
private(set) weak var value: T?
init(value: T?) {
self.value = value
}
}
如何解决此错误?应当按照site正确声明代表。
到目前为止,我已经尝试过:
AnyObject
更改为
class
无法解决问题。答案 0 :(得分:6)
您不能拥有WeakReference<ServiceDelegate>
。 ServiceDelegate
本身不是AnyObject
,它只要求符合它的任何内容都是AnyObject
。
您需要将SomeClass
设为通用,并使用通用类型作为WeakReference
的类型:
class SomeClass<T: ServiceDelegate> {
private var observers = [WeakReference<T>]()
}
如果SomeClass
上的泛型过于狭窄,并且您希望能够以多个不相关类的实例作为观察者,那么我可以通过放弃WeakReference
上的泛型参数来做到这一点:
final class WeakServiceDelegate {
private(set) weak var value: ServiceDelegate?
init(value: ServiceDelegate?) {
self.value = value
}
}
class SomeClass {
private var observers = [WeakServiceDelegate]()
}
或者,您可以使WeakReference
有条件地符合ServiceDelegate
:
extension WeakReference: ServiceDelegate where T: ServiceDelegate {
func doIt() {
value?.doIt()
}
}
然后在ServiceDelegate
中使用SomeClass
数组:
class SomeClass {
private var observers = [ServiceDelegate]()
func addObserver<T: ServiceDelegate>(_ observer: T) {
observers.append(WeakReference(value: observer))
}
}
答案 1 :(得分:4)
如您所见,ServiceDelegate
是协议,而不是类类型。
即使所有符合ServiceDelegate
的类型都是类类型,ServiceDelegate
本身也不是类类型。这是目前纯Swift协议的事实。
尝试@obc
,Objective-C协议有点不同:
@objc protocol ServiceDelegate {
func doIt()
}
您可能要排除Objective-C某些内容,并使某些纯Swift类符合ServiceDelegate
,但我找不到其他解决方法。
答案 2 :(得分:3)
问题是WeakReference<ServiceDelegate>
在行上是错误的
private var observers = [WeakReference<ServiceDelegate>]()
您必须在<>
内使用具体的类而不是协议
您有两种可能的解决方案:
class ServiceClass: ServiceDelegate { //... } private var observers = [WeakReference<ServiceClass>]()
或使用协议。我的意思是:
final class WeakReference<T: AnyObject> {
private(set) weak var value: T?
init(value: T?) {
self.value = value
}
}
protocol SomeContainer: AnyObject { }
extension WeakReference: SomeContainer { }
并使用这种方式:
private var observers = [SomeContainer]()
注意
使用这种方式:
class SomeClass<T: ServiceDelegate> {
private var observers = [WeakReference<T>]()
}
您只需将问题移至代码的另一部分。
答案 3 :(得分:0)
创建普通协议
public protocol AnyWeakValue {
var anyValue: Any? { get }
}
AnyWeakValue
的继承关联类型协议public protocol WeakValue: AnyWeakValue {
associatedtype ValueType
var value: ValueType? { get }
}
extension WeakValue {
public var anyValue: Any? { return value }
}
创建类Weak继承 WeakValue
open class Weak<Value: AnyObject>: WeakValue {
public init(value: Value?) { self.value = value }
open private(set) weak var value: Value?
}
使用示例
private var _delegates: [AnyWeakValue] = []
public var delegates: [SomeProtocol] {
return _delegates.compactMap({$0.anyValue as? SomeProtocol})
}
public func register<Delegate>(_ delegate: Delegate) where Delegate: SomeProtocol {
let weak: Weak<Delegate> = Weak.init(value: delegate)
_delegates.append(weak)
}
答案 4 :(得分:0)
我遇到了类似的问题,最终保留了通用WeakReference
,但是删除了类型约束:
struct WeakReference<T> {
private weak var storage: AnyObject?
var value: T? {
get { return storage.map { $0 as! T } }
set {
storage = newValue.map { $0 as AnyObject }
}
}
init(value: T?) {
self.value = value
}
}
这适用于类,Objective-C协议和Swift协议:
protocol P: class {}
@objc protocol Q {}
class Z: P, Q {}
var z = Z()
var rz = WeakReference<Z>(value: z)
var rp = WeakReference<P>(value: z)
var rq = WeakReference<Q>(value: z)
assert(rz.value === z)
assert(rp.value === z)
assert(rq.value === z)
z = Z()
assert(rz.value === nil)
assert(rp.value === nil)
assert(rq.value === nil)
不幸的是,它也可以编译其他东西:
protocol R {}
struct S: R {}
var rr = WeakReference<R>(value: S())
print("rr =", rr.value as Any) // nil
var rs = WeakReference<S>(value: S())
print("rs =", rs.value as Any) // nil
在Swift中,任何东西都可以转换为AnyObject
,但是对于意味着装箱的值类型-新实例被分配并立即丢失,因此它总是产生nil。
这可以用来实现一个断言,强制转换为AnyObject
可以保留身份:
struct WeakReference<T> {
private weak var storage: AnyObject?
var value: T? {
get { return storage.map { $0 as! T } }
set {
storage = newValue.map {
let asObject = $0 as AnyObject
assert(asObject === $0 as AnyObject)
return asObject
}
}
}
init(value: T?) {
self.value = value
}
}
另一种方法是使用https://github.com/wickwirew/Runtime来验证T.self
的种类。