[英]type A requires that type B be a class type swift 4
the following code gives me a compile error下面的代码给了我一个编译错误
'WeakReference' requires that 'ServiceDelegate' be a class type 'WeakReference' 要求 'ServiceDelegate' 是一个类类型
protocol ServiceDelegate: AnyObject {
func doIt()
}
class SomeClass() {
// compile error occurs in this line
private var observers = [WeakReference<ServiceDelegate>]()
}
WeakReference code:弱引用代码:
final class WeakReference<T: AnyObject> {
private(set) weak var value: T?
init(value: T?) {
self.value = value
}
}
How can I fix this error?我该如何解决这个错误? Delegate should be declared correctly as per this site .代表应按照本 网站正确声明。
What I have tried so far:到目前为止我尝试过的:
AnyObject
to class
does not solve the problem.将委托协议一致性从AnyObject
更改为class
并不能解决问题。You can't have a WeakReference<ServiceDelegate>
.你不能有WeakReference<ServiceDelegate>
。 ServiceDelegate
itself is not an AnyObject
, it just requires that anything that conforms to it be an AnyObject
. ServiceDelegate
本身不是AnyObject
,它只要求符合它的任何东西都是AnyObject
。
You would need to make SomeClass
generic and use the generic type as the type for the WeakReference
:您需要使SomeClass
泛型并使用泛型类型作为WeakReference
的类型:
class SomeClass<T: ServiceDelegate> {
private var observers = [WeakReference<T>]()
}
If the generic on SomeClass
is too constricting and you want to be able to have instances of multiple unrelated classes as observers then I would do it by abandoning the generic parameter on WeakReference
:如果SomeClass
上的泛型过于严格,并且您希望能够将多个不相关类的实例作为观察者,那么我会通过放弃WeakReference
上的泛型参数WeakReference
:
final class WeakServiceDelegate {
private(set) weak var value: ServiceDelegate?
init(value: ServiceDelegate?) {
self.value = value
}
}
class SomeClass {
private var observers = [WeakServiceDelegate]()
}
Alternatively you could make WeakReference
conditionally conform to ServiceDelegate
:或者,您可以使WeakReference
有条件地符合ServiceDelegate
:
extension WeakReference: ServiceDelegate where T: ServiceDelegate {
func doIt() {
value?.doIt()
}
}
And then use an array of ServiceDelegate
in SomeClass
:然后在SomeClass
使用ServiceDelegate
数组:
class SomeClass {
private var observers = [ServiceDelegate]()
func addObserver<T: ServiceDelegate>(_ observer: T) {
observers.append(WeakReference(value: observer))
}
}
As you see, ServiceDelegate
is a protocol, not a class type.如您所见, ServiceDelegate
是一种协议,而不是类类型。 Even if all types which can conform to ServiceDelegate
are class types, ServiceDelegate
itself is not a class type.即使所有可以符合ServiceDelegate
的类型都是类类型, ServiceDelegate
本身也不是类类型。 It is the fact of the pure Swift protocols currently.这是目前纯 Swift 协议的事实。
Try @obc
, Objective-C protocols are a bit different:试试@obc
,Objective-C 协议有点不同:
@objc protocol ServiceDelegate {
func doIt()
}
You may want to exclude Objective-C something and to make some pure Swift classes conform to ServiceDelegate
, but I cannot find other ways around.您可能想要排除 Objective-C 的内容并使一些纯 Swift 类符合ServiceDelegate
,但我找不到其他方法。
The problem is that WeakReference<ServiceDelegate>
is wrong at line问题是WeakReference<ServiceDelegate>
在线错误
private var observers = [WeakReference<ServiceDelegate>]()
You have to use a concrete class instead of protocol inside <>
您必须在<>
使用具体类而不是协议
You have two possible solutions:您有两种可能的解决方案:
class ServiceClass: ServiceDelegate { //... } private var observers = [WeakReference<ServiceClass>]()
Or use a protocol.或者使用协议。 I mean this:我的意思是:
final class WeakReference<T: AnyObject> { private(set) weak var value: T? init(value: T?) { self.value = value } } protocol SomeContainer: AnyObject { } extension WeakReference: SomeContainer { }
and use this way:并使用这种方式:
private var observers = [SomeContainer]()
Note笔记
Using this way:使用这种方式:
class SomeClass<T: ServiceDelegate> {
private var observers = [WeakReference<T>]()
}
You just move the problem to another part of the code.您只需将问题移至代码的另一部分即可。
create plain protocol创建普通协议
public protocol AnyWeakValue {
var anyValue: Any? { get }
}
inherit associatedtype protocol from AnyWeakValue从AnyWeakValue继承关联类型协议
public protocol WeakValue: AnyWeakValue {
associatedtype ValueType
var value: ValueType? { get }
}
extension WeakValue {
public var anyValue: Any? { return value }
}
create class Weak inherit WeakValue创建类 Weak 继承WeakValue
open class Weak<Value: AnyObject>: WeakValue {
public init(value: Value?) { self.value = value }
open private(set) weak var value: Value?
}
using example使用示例
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)
}
I had similar problem and ended up keeping generic WeakReference
, but removing type constraint:我遇到了类似的问题,最终保留了通用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
}
}
This works for classes, Objective-C protocols and Swift protocols:这适用于类、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)
Unfortunately it compiles for other things too:不幸的是,它也为其他东西编译:
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
In Swift anything can be casted to AnyObject
, but for value types that means boxing - new instance is allocated and immediately lost, so it always produces nil.在 Swift 中,任何东西都可以转换为AnyObject
,但对于值类型意味着装箱 - 新实例被分配并立即丢失,因此它总是产生 nil。
This can be used to implement an assertion that casting to AnyObject
preserves identity:这可用于实现强制转换为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
}
}
Alternative approach would be to use https://github.com/wickwirew/Runtime to validate kind of T.self
.替代方法是使用https://github.com/wickwirew/Runtime来验证T.self
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.