不支持用作符合协议 AnyObject 的具体类型
Posted
技术标签:
【中文标题】不支持用作符合协议 AnyObject 的具体类型【英文标题】:Using as a concrete type conforming to protocol AnyObject is not supported 【发布时间】:2015-12-24 19:22:23 【问题描述】:我正在使用 Swift 2 并使用 WeakContainer 作为存储一组弱对象的一种方式,很像 NSHashTable.weakObjectsHashTable()
struct WeakContainer<T: AnyObject>
weak var value: T?
public protocol MyDelegate : AnyObject
然后在我的 ViewController 中,我声明
public var delegates = [WeakContainer<MyDelegate>]
但这是错误
不支持将 MyDelegate 用作符合协议 AnyObject 的具体类型
我看到错误是WeakContainer
将value
成员声明为weak
,因此T
应该是对象。但我也将MyDelegate
声明为AnyObject
。如何解决这个问题?
【问题讨论】:
错误到底在哪里?NSHashTable
有什么问题?
在您的协议声明中,如果您将AnyObject
更改为class
,它应该可以正常工作。不过不要让我解释其中的区别。
i.imgur.com/B0swn6w.png
有人提出解决方案了吗?遭受完全相同的问题...
还没有修复。这是描述相同问题的 jira 票证:bugs.swift.org/browse/SR-1176
【参考方案1】:
我在尝试实现弱容器时遇到了同样的问题。正如@plivesey 在上面的评论中指出的那样,这似乎是 Swift 2.2 / Xcode 7.3 中的 bug,但它是 expected to work。
但是,某些基金会协议不会出现此问题。例如,这样编译:
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
的值失败。
【讨论】:
解决方法 2 在这里工作得很好,当然它不应该是必需的!伟大的工作。 解决方法 2 使我免于大规模重写。谢谢@Theo 帅哥!您是如何发现 Workaround2 的?它工作得很好。而且 Workaround1 就像魔术一样! 在线_value = newValue as? AnyObject
上获得警告Conditional cast from 'T?' to 'AnyObject' always succeeds
。我们应该怎么做?【参考方案2】:
我也有同样的想法,用泛型创建弱容器。
结果,我为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
协议,那么app就会崩溃。但我目前没有看到任何更好的解决方案。
【讨论】:
object is AnyObject
始终为真。【参考方案3】:
您为什么要尝试使用泛型?我建议执行以下操作:
import Foundation
import UIKit
protocol MyDelegate : AnyObject
class WeakContainer : AnyObject
weak var value: MyDelegate?
class ViewController: UIViewController
var delegates = [WeakContainer]()
还有NSValue
的nonretainedObject
【讨论】:
您建议的WeakContainer
只能存储MyDelegate
类型的值。问题是如何实现这个容器,以便它也可以被其他协议重用。【参考方案4】:
如果您的协议可以标记为@obj,那么您可以使用下面的代码
protocol Observerable
associatedtype P : AnyObject
var delegates: NSHashTable<P> get
@objc protocol MyProtocol
func someFunc()
class SomeClass : Observerable
var delegates = NSHashTable<MyProtocol>.weakObjects()
【讨论】:
【参考方案5】:您的问题是 WeakContainer
要求其泛型类型 T
是 AnyObject
的子类型 - protocol
声明 不是 AnyObject
的子类型。您有四个选择:
不要声明WeakContainer<MyDelegate>
,而是用实际实现MyDelegate
的东西替换它。 Swift-y 的方法是使用 AnyX
模式:struct AnyMyDelegate : MyDelegate ...
将MyDelegate
定义为“类绑定”为protocol MyDelegate : class ...
用@obj
注释MyDelegate
,这基本上使它成为“类绑定”
将WeakContainer
重新表述为不要求其泛型类型从AnyObject
继承。您将很难完成这项工作,因为您需要一个声明为 weak var
的属性,并且 weak var
接受的类型存在限制 - 本质上是 AnyObject
。
【讨论】:
关于选项2:这里class
和AnyObject
的效果不一样吗?当我尝试它时,它似乎没有任何区别。至于选项 4:据我了解,从 AnyObject
继承是使泛型类型绑定类的唯一方法。您能否提供选项 2 和 4 的示例实现?【参考方案6】:
这是我在纯 Swift 中实现的 WeakSet(没有 NSHashTable)。
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
【讨论】:
这不能用 swift 3 编译以上是关于不支持用作符合协议 AnyObject 的具体类型的主要内容,如果未能解决你的问题,请参考以下文章
类型'[String,AnyObject?]'不符合协议AnyObject?:为什么?
类型 [String: String] 不符合协议 'AnyObject'
类型“AnyObject”不符合协议“NSFetchRequestResult”
类型“NSFastEnumerationIterator.Element”(又名“Any”)不符合协议“AnyObject”