37

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

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

public protocol MyDelegate : AnyObject {

}

然后在我的 ViewController 中,我声明

public var delegates = [WeakContainer<MyDelegate>]

但这是错误

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

我看到错误是成员声明为WeakContainer,因此应该是对象。但我也声明为。如何解决这个问题?valueweakTMyDelegateAnyObject

4

6 回答 6

18

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

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

let container = WeakContainer<NSCacheDelegate>()

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

解决方法 1

@objc
public protocol MyDelegate : AnyObject { }

let container = WeakContainer<MyDelegate>() // No compiler error

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

警告:设置一个符合T, 但不是AnyObject, 的值失败。

于 2016-04-28T11:27:30.930 回答
11

我有同样的想法用泛型创建弱容器。
结果,我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?
        }
    }
}

用法:

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()
}

这不是最好的解决方案,因为WeakSet可以用任何类型初始化,如果这种类型不符合AnyObject协议,那么应用程序就会崩溃。但我现在没有看到任何更好的解决方案。

于 2015-11-14T05:32:24.743 回答
5

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

import Foundation
import UIKit

protocol MyDelegate : AnyObject {

}

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

class ViewController: UIViewController {
    var delegates = [WeakContainer]()
}

还有NSValuenonretainedObject

于 2015-11-10T03:45:33.787 回答
3

如果您的协议可以标记为@obj,那么您可以使用下面的代码

protocol Observerable {

    associatedtype P : AnyObject

    var delegates: NSHashTable<P> { get }
}

@objc protocol MyProtocol {

    func someFunc()

}

class SomeClass : Observerable {

    var delegates = NSHashTable<MyProtocol>.weakObjects()

}
于 2017-04-09T08:42:46.323 回答
1

您的问题是WeakContainer要求其泛型类型T是的子类型AnyObject-protocol声明不是AnyObject. 您有四个选择:

  1. 而不是声明WeakContainer<MyDelegate>用实际实现的东西替换它MyDelegate。Swift-y 的方法是使用以下AnyX模式:struct AnyMyDelegate : MyDelegate { ... }

  2. 定义MyDelegate为“类绑定”为protocol MyDelegate : class { ... }

  3. MyDelegate使用which 进行注释@obj,本质上,使其成为“类绑定”

  4. 重新WeakContainer制定要求其泛型类型继承自AnyObject. 您将很难完成这项工作,因为您需要一个声明为的属性,weak var并且对于接受哪些类型存在限制weak var-AnyObject本质上是。

于 2016-04-28T14:05:41.643 回答
0

这是我在纯 Swift 中实现的 WeakSet(没有 NSHashTable)。

internal struct WeakBox<T: AnyObject> {
    internal private(set) weak var value: T?
    private var pointer: UnsafePointer<Void>
    internal init(_ value: T) {
        self.value = value
        self.pointer = unsafeAddressOf(value)
    }
}


extension WeakBox: Hashable {
    var hashValue: Int {
        return self.pointer.hashValue
    }
}


extension WeakBox: Equatable {}

func ==<T>(lhs: WeakBox<T>, rhs: WeakBox<T>) -> Bool {
    return lhs.pointer == rhs.pointer
}



public struct WeakSet<Element>: SequenceType {
    private var boxes = Set<WeakBox<AnyObject>>()

    public mutating func insert(member: Element) {
        guard let object = member as? AnyObject else {
            fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
        }

        self.boxes.insert(WeakBox(object))
    }

    public mutating func remove(member: Element) {
        guard let object = member as? AnyObject else {
            fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
        }

        self.boxes.remove(WeakBox(object))
    }

    public mutating func removeAll() {
        self.boxes.removeAll()
    }

    public func contains(member: Element) -> Bool {
        guard let object = member as? AnyObject else {
            fatalError("WeakSet's member (\(member)) must conform to AnyObject protocol.")
        }

        return self.boxes.contains(WeakBox(object))
    }

    public func generate() -> AnyGenerator<Element> {
        var generator = self.boxes.generate()

        return AnyGenerator {
            while(true) {
                guard let box = generator.next() else {
                    return nil
                }

                guard let element = box.value else {
                    continue
                }

                return element as? Element
            }
        }
    }
}
于 2016-05-02T17:43:20.453 回答