使用符合协议AnyObject的具体类型不受支持

onm*_*133 33 protocols reference hashtable weak swift

我正在使用Swift 2并使用WeakContainer作为存储一组弱对象的方式,就像 NSHashTable.weakObjectsHashTable()

struct WeakContainer<T: AnyObject> {
    weak var value: T?
}

public protocol MyDelegate : AnyObject {

}
Run Code Online (Sandbox Code Playgroud)

然后在我的ViewController中,我声明

public var delegates = [WeakContainer<MyDelegate>]
Run Code Online (Sandbox Code Playgroud)

但这是错误的

使用MyDelegate作为符合协议AnyObject的具体类型不受支持

我看到的错误是,WeakContainer具有value声明为成员weak,因此T有望成为对象.但我也声明MyDelegateAnyObject也.怎么解决这个问题?

The*_*heo 16

当我尝试实现弱容器时遇到了同样的问题.正如@plivesey在上面的评论中指出的那样,这似乎是Swift 2.2/Xcode 7.3中的一个错误,但预计会有效.

但是,某些Foundation协议不会出现此问题.例如,这编译:

let container = WeakContainer<NSCacheDelegate>()
Run Code Online (Sandbox Code Playgroud)

我发现这适用于标有该@objc属性的协议.您可以将其用作解决方法:

解决方法1

@objc
public protocol MyDelegate : AnyObject { }

let container = WeakContainer<MyDelegate>() // No compiler error
Run Code Online (Sandbox Code Playgroud)

由于这可能导致其他问题(某些类型无法在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
Run Code Online (Sandbox Code Playgroud)

警告:保存符合T但不符合的值AnyObject.

  • 解决方法2在这里很好用,但当然不应该需要它!做得好. (2认同)
  • 解决方法2使我免于大规模重写.谢谢@Theo (2认同)

Vla*_*pko 12

我有同样的想法用泛型创建弱容器.
结果我创建了包装器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?
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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()
}
Run Code Online (Sandbox Code Playgroud)

它不是最好的解决方案,因为WeakSet可以使用任何类型进行初始化,如果此类型不符合AnyObject协议,则应用程序将崩溃.但我现在没有看到任何更好的解决方案.


Kyl*_*arn 5

你为什么要尝试使用泛型?我建议执行以下操作:

import Foundation
import UIKit

protocol MyDelegate : AnyObject {

}

class WeakContainer : AnyObject {
    weak var value: MyDelegate?
}

class ViewController: UIViewController {
    var delegates = [WeakContainer]()
}
Run Code Online (Sandbox Code Playgroud)

还有NSValuenonretainedObject

  • 您建议的“WeakContainer”只能存储“MyDelegate”类型的值。问题是如何实现这个容器,以便它也可以重用于其他协议。 (3认同)