不支持使用符合协议 AnyObject 的具体类型
Using as a concrete type conforming to protocol AnyObject is not supported
我正在使用 Swift 2 并使用 WeakContainer 作为存储一组弱对象的方式,很像 NSHashTable.weakObjectsHashTable()
struct WeakContainer<T: AnyObject> {
weak var value: T?
}
public protocol MyDelegate : AnyObject {
}
然后在我的ViewController中声明
public var delegates = [WeakContainer<MyDelegate>]
但是报错
Using MyDelegate as a concrete type conforming to protocol AnyObject is not supported
我看到错误是 WeakContainer
有 value
成员声明为 weak
,所以 T
应该是对象。但我也将 MyDelegate
声明为 AnyObject
。如何解决这个问题?
您为什么要尝试使用泛型?我建议执行以下操作:
import Foundation
import UIKit
protocol MyDelegate : AnyObject {
}
class WeakContainer : AnyObject {
weak var value: MyDelegate?
}
class ViewController: UIViewController {
var delegates = [WeakContainer]()
}
还有NSValue
的nonretainedObject
我有同样的想法用泛型创建弱容器。
结果,我为 NSHashTable
创建了包装器,并为您的编译器错误做了一些解决方法。
class WeakSet<ObjectType>: SequenceType {
var count: Int {
return weakStorage.count
}
private let weakStorage = NSHashTable.weakObjectsHashTable()
func addObject(object: ObjectType) {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
weakStorage.addObject(object as? AnyObject)
}
func removeObject(object: ObjectType) {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
weakStorage.removeObject(object as? AnyObject)
}
func removeAllObjects() {
weakStorage.removeAllObjects()
}
func containsObject(object: ObjectType) -> Bool {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
return weakStorage.containsObject(object as? AnyObject)
}
func generate() -> AnyGenerator<ObjectType> {
let enumerator = weakStorage.objectEnumerator()
return anyGenerator {
return enumerator.nextObject() as! ObjectType?
}
}
}
用法:
protocol MyDelegate : AnyObject {
func doWork()
}
class MyClass: AnyObject, MyDelegate {
fun doWork() {
// Do delegated work.
}
}
var delegates = WeakSet<MyDelegate>()
delegates.addObject(MyClass())
for delegate in delegates {
delegate.doWork()
}
这不是最好的解决方案,因为 WeakSet
可以用任何类型初始化,如果此类型不符合 AnyObject
协议,应用程序将崩溃。但是我现在没有看到更好的解决方案。
我 运行 在尝试实现弱容器时遇到了同样的问题。正如@plivesey 在上面的评论中指出的那样,这似乎是 bug in Swift 2.2 / Xcode 7.3, but it is expected to work.
但是,某些 Foundation 协议不会出现此问题。例如,这样编译:
let container = WeakContainer<NSCacheDelegate>()
我发现这适用于标有 @objc
属性的协议。您可以使用此作为解决方法:
解决方法 1
@objc
public protocol MyDelegate : AnyObject { }
let container = WeakContainer<MyDelegate>() // No compiler error
因为这会导致其他问题(某些类型无法在 Objective-C 中表示),这里有一个替代方法:
解决方法 2
从容器中删除 AnyObject
要求,并在内部将值转换为 AnyObject
。
struct WeakContainer<T> {
private weak var _value:AnyObject?
var value: T? {
get {
return _value as? T
}
set {
_value = newValue as? AnyObject
}
}
}
protocol MyDelegate : AnyObject { }
var container = WeakContainer<MyDelegate>() // No compiler error
警告:设置符合 T
但不是 AnyObject
的值会失败。
您的问题是 WeakContainer
要求其通用类型 T
是 AnyObject
的子类型 - protocol
声明 不是 AnyObject
的子类型。您有四个选择:
而不是声明 WeakContainer<MyDelegate>
将其替换为实际实现的东西 MyDelegate
。 Swift-y 方法是使用 AnyX
模式:struct AnyMyDelegate : MyDelegate { ... }
定义 MyDelegate
为 'class bound' as protocol MyDelegate : class { ... }
用 @obj
注释 MyDelegate
,本质上,这使得它 'class bound'
将 WeakContainer
重新表述为 ,而不是 要求其泛型类型继承自 AnyObject
。你将很难完成这项工作,因为你需要一个声明为 weak var
的 属性 并且 weak var
接受的类型是有限制的 - AnyObject
本质上。
这是我在纯 Swift(没有 NSHashTable)中实现的 WeakSet。
internal struct WeakBox<T: AnyObject> {
internal private(set) weak var value: T?
private var pointer: UnsafePointer<Void>
internal init(_ value: T) {
self.value = value
self.pointer = unsafeAddressOf(value)
}
}
extension WeakBox: Hashable {
var hashValue: Int {
return self.pointer.hashValue
}
}
extension WeakBox: Equatable {}
func ==<T>(lhs: WeakBox<T>, rhs: WeakBox<T>) -> Bool {
return lhs.pointer == rhs.pointer
}
public struct WeakSet<Element>: SequenceType {
private var boxes = Set<WeakBox<AnyObject>>()
public mutating func insert(member: Element) {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
self.boxes.insert(WeakBox(object))
}
public mutating func remove(member: Element) {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
self.boxes.remove(WeakBox(object))
}
public mutating func removeAll() {
self.boxes.removeAll()
}
public func contains(member: Element) -> Bool {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
return self.boxes.contains(WeakBox(object))
}
public func generate() -> AnyGenerator<Element> {
var generator = self.boxes.generate()
return AnyGenerator {
while(true) {
guard let box = generator.next() else {
return nil
}
guard let element = box.value else {
continue
}
return element as? Element
}
}
}
}
如果您的协议可以标记为@obj,那么您可以使用下面的代码
protocol Observerable {
associatedtype P : AnyObject
var delegates: NSHashTable<P> { get }
}
@objc protocol MyProtocol {
func someFunc()
}
class SomeClass : Observerable {
var delegates = NSHashTable<MyProtocol>.weakObjects()
}
我正在使用 Swift 2 并使用 WeakContainer 作为存储一组弱对象的方式,很像 NSHashTable.weakObjectsHashTable()
struct WeakContainer<T: AnyObject> {
weak var value: T?
}
public protocol MyDelegate : AnyObject {
}
然后在我的ViewController中声明
public var delegates = [WeakContainer<MyDelegate>]
但是报错
Using MyDelegate as a concrete type conforming to protocol AnyObject is not supported
我看到错误是 WeakContainer
有 value
成员声明为 weak
,所以 T
应该是对象。但我也将 MyDelegate
声明为 AnyObject
。如何解决这个问题?
您为什么要尝试使用泛型?我建议执行以下操作:
import Foundation
import UIKit
protocol MyDelegate : AnyObject {
}
class WeakContainer : AnyObject {
weak var value: MyDelegate?
}
class ViewController: UIViewController {
var delegates = [WeakContainer]()
}
还有NSValue
的nonretainedObject
我有同样的想法用泛型创建弱容器。
结果,我为 NSHashTable
创建了包装器,并为您的编译器错误做了一些解决方法。
class WeakSet<ObjectType>: SequenceType {
var count: Int {
return weakStorage.count
}
private let weakStorage = NSHashTable.weakObjectsHashTable()
func addObject(object: ObjectType) {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
weakStorage.addObject(object as? AnyObject)
}
func removeObject(object: ObjectType) {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
weakStorage.removeObject(object as? AnyObject)
}
func removeAllObjects() {
weakStorage.removeAllObjects()
}
func containsObject(object: ObjectType) -> Bool {
guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
return weakStorage.containsObject(object as? AnyObject)
}
func generate() -> AnyGenerator<ObjectType> {
let enumerator = weakStorage.objectEnumerator()
return anyGenerator {
return enumerator.nextObject() as! ObjectType?
}
}
}
用法:
protocol MyDelegate : AnyObject {
func doWork()
}
class MyClass: AnyObject, MyDelegate {
fun doWork() {
// Do delegated work.
}
}
var delegates = WeakSet<MyDelegate>()
delegates.addObject(MyClass())
for delegate in delegates {
delegate.doWork()
}
这不是最好的解决方案,因为 WeakSet
可以用任何类型初始化,如果此类型不符合 AnyObject
协议,应用程序将崩溃。但是我现在没有看到更好的解决方案。
我 运行 在尝试实现弱容器时遇到了同样的问题。正如@plivesey 在上面的评论中指出的那样,这似乎是 bug in Swift 2.2 / Xcode 7.3, but it is expected to work.
但是,某些 Foundation 协议不会出现此问题。例如,这样编译:
let container = WeakContainer<NSCacheDelegate>()
我发现这适用于标有 @objc
属性的协议。您可以使用此作为解决方法:
解决方法 1
@objc
public protocol MyDelegate : AnyObject { }
let container = WeakContainer<MyDelegate>() // No compiler error
因为这会导致其他问题(某些类型无法在 Objective-C 中表示),这里有一个替代方法:
解决方法 2
从容器中删除 AnyObject
要求,并在内部将值转换为 AnyObject
。
struct WeakContainer<T> {
private weak var _value:AnyObject?
var value: T? {
get {
return _value as? T
}
set {
_value = newValue as? AnyObject
}
}
}
protocol MyDelegate : AnyObject { }
var container = WeakContainer<MyDelegate>() // No compiler error
警告:设置符合 T
但不是 AnyObject
的值会失败。
您的问题是 WeakContainer
要求其通用类型 T
是 AnyObject
的子类型 - protocol
声明 不是 AnyObject
的子类型。您有四个选择:
而不是声明
WeakContainer<MyDelegate>
将其替换为实际实现的东西MyDelegate
。 Swift-y 方法是使用AnyX
模式:struct AnyMyDelegate : MyDelegate { ... }
定义
MyDelegate
为 'class bound' asprotocol MyDelegate : class { ... }
用
@obj
注释MyDelegate
,本质上,这使得它 'class bound'将
WeakContainer
重新表述为 ,而不是 要求其泛型类型继承自AnyObject
。你将很难完成这项工作,因为你需要一个声明为weak var
的 属性 并且weak var
接受的类型是有限制的 -AnyObject
本质上。
这是我在纯 Swift(没有 NSHashTable)中实现的 WeakSet。
internal struct WeakBox<T: AnyObject> {
internal private(set) weak var value: T?
private var pointer: UnsafePointer<Void>
internal init(_ value: T) {
self.value = value
self.pointer = unsafeAddressOf(value)
}
}
extension WeakBox: Hashable {
var hashValue: Int {
return self.pointer.hashValue
}
}
extension WeakBox: Equatable {}
func ==<T>(lhs: WeakBox<T>, rhs: WeakBox<T>) -> Bool {
return lhs.pointer == rhs.pointer
}
public struct WeakSet<Element>: SequenceType {
private var boxes = Set<WeakBox<AnyObject>>()
public mutating func insert(member: Element) {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
self.boxes.insert(WeakBox(object))
}
public mutating func remove(member: Element) {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
self.boxes.remove(WeakBox(object))
}
public mutating func removeAll() {
self.boxes.removeAll()
}
public func contains(member: Element) -> Bool {
guard let object = member as? AnyObject else {
fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
}
return self.boxes.contains(WeakBox(object))
}
public func generate() -> AnyGenerator<Element> {
var generator = self.boxes.generate()
return AnyGenerator {
while(true) {
guard let box = generator.next() else {
return nil
}
guard let element = box.value else {
continue
}
return element as? Element
}
}
}
}
如果您的协议可以标记为@obj,那么您可以使用下面的代码
protocol Observerable {
associatedtype P : AnyObject
var delegates: NSHashTable<P> { get }
}
@objc protocol MyProtocol {
func someFunc()
}
class SomeClass : Observerable {
var delegates = NSHashTable<MyProtocol>.weakObjects()
}