简体   繁体   English

类型 A 要求类型 B 是一个类类型 swift 4

[英]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:到目前为止我尝试过的:

  • Changing the delegate protocol conformance from AnyObject to class does not solve the problem.将委托协议一致性从AnyObject更改为class并不能解决问题。
  • Try the above code in a clean playground.在干净的操场上尝试上面的代码。

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:您有两种可能的解决方案:

  1. Create a concrete class and use it:创建一个具体的类并使用它:
 class ServiceClass: ServiceDelegate { //... } private var observers = [WeakReference<ServiceClass>]()
  1. 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 AnyWeakValueAnyWeakValue继承关联类型协议

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM