Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 704
onmyway133 Avatar asked Sep 27 '15 12:09

onmyway133


Video Answer


2 Answers

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.

like image 198
Theo Avatar answered Sep 25 '22 08:09

Theo


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.

like image 33
Vlad Papko Avatar answered Sep 25 '22 08:09

Vlad Papko