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

时间:2018-07-23 20:44:18

标签: swift swift4

以下代码给我一个编译错误

  

“ 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无法解决问题。
  • 在干净的操场上尝试上面的代码。

5 个答案:

答案 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>]()

您必须在<>内使用具体的类而不是协议

您有两种可能的解决方案:

  1. 创建一个具体的类并使用它:
class ServiceClass: ServiceDelegate {
//...
}
private var observers = [WeakReference<ServiceClass>]()
  1. 或使用协议。我的意思是:

     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的种类。