I'm using Swift 2 and using WeakContainer as a way to store a set of weak objects, much like NSHashTable.weakObjectsHashTable()
struct WeakContainer<T: AnyObject> { weak var value: T? } public protocol MyDelegate : AnyObject { }
Then in my ViewController, I declare
public var delegates = [WeakContainer<MyDelegate>]
But it is error
Using MyDelegate as a concrete type conforming to protocol AnyObject is not supported
I see that the error is that WeakContainer
has value
member declared as weak
, so T
is expected to be object. But I also declare MyDelegate
as AnyObject
, too. How to get around this?
I ran into the same problem when I tried to implement weak containers. As @plivesey points out in a comment above, this seems to be a bug in Swift 2.2 / Xcode 7.3, but it is expected to work.
However, the problem does not occur for some Foundation protocols. For example, this compiles:
let container = WeakContainer<NSCacheDelegate>()
I found out that this works for protocols marked with the @objc
attribute. You can use this as a workaround:
Workaround 1
@objc public protocol MyDelegate : AnyObject { } let container = WeakContainer<MyDelegate>() // No compiler error
As this can lead to other problems (some types cannot be represented in Objective-C), here is an alternative approach:
Workaround 2
Drop the AnyObject
requirement from the container, and cast the value to AnyObject
internally.
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
Caveat: Setting a value that conforms to T
, but is not an AnyObject
, fails.
I had the same idea to create weak container with generics.
As result I created wrapper for NSHashTable
and did some workaround for your compiler error.
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? } } }
Usage:
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() }
It's not the best solution, because WeakSet
can be initialized with any type, and if this type doesn't conform to AnyObject
protocol then app will crash. But I don't see any better solution right now.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With