swiftreferencehashtableprotocolsweak

Using as a concrete type conforming to protocol AnyObject is not supported


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?


Solution

  • 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.