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

onmyway133 picture onmyway133 · Sep 27, 2015 · Viewed 9.1k times · Source

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?

Answer

Theo picture Theo · Apr 28, 2016

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.