2015-09-27 75 views
32

我使用斯威夫特2和使用WeakContainer作为一种存储一组弱的对象,就像NSHashTable.weakObjectsHashTable()使用作为具体类型符合协议AnyObject不支持

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

public protocol MyDelegate : AnyObject { 

} 

然后在我的ViewController,我声明

public var delegates = [WeakContainer<MyDelegate>] 

但它是错误

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

我看到的错误是,WeakContainer宣布为weakvalue成员,因此T预期为对象。但我也宣布MyDelegateAnyObject。如何解决这个问题?

+0

哪里是错误实际上是在使用代码? “NSHashTable”有什么问题? – nhgrif

+0

在协议声明中,如果将'AnyObject'更改为'class',它应该可以正常工作。不要问我解释不同之处。 – nhgrif

+0

@nhgrif我试过'公共协议MyDelegate:类'之前,它不起作用 – onmyway133

回答

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协议,然后应用程序会崩溃。但我现在看不到更好的解决方案。

2

你为什么试图使用泛型?我建议做以下几点:

import Foundation 
import UIKit 

protocol MyDelegate : AnyObject { 

} 

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

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

还有NSValuenonretainedObject

+2

您建议'WeakContainer'只能存储“MyDelegate”类型的值。问题是如何实现这个容器,以便它可以重用于其他协议。 – Theo

14

我试图实现弱容器时遇到了同样的问题。正如@plivesey在上面的评论中指出的那样,这似乎是Swift 2.2/Xcode 7.3中的bug,但它是expected to work

但是,某些Foundation协议不会发生此问题。例如,该编译:

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小号失败。

+1

解决方法2在这里很好地工作,当然它不应该需要!做得好。 – HughHughTeotl

+1

解决方法2将我从大规模重写中拯救出来。谢谢@Theo –

+0

酷小伙!你是如何发现Workaround2的?它工作得很好。还有解决方法1就像魔术一样! – Pandara

1

你的问题是,WeakContainer要求其通用型T是的AnyObject一个亚型 - 一个声明不是AnyObject亚型。您有四个选项:

  1. ,而不用声明WeakContainer<MyDelegate>的东西,真正实现MyDelegate更换的。造成这种情况的夫特-Y的方法是使用所述AnyX图案:struct AnyMyDelegate : MyDelegate { ... }

  2. 定义MyDelegate是“类结合的”作为protocol MyDelegate : class { ... }

  3. 标注MyDelegate@obj其中,本质上,使得“类结合的”

  4. 重新调整WeakContainer而不是要求其通用类型继承自AnyObject。你很难完成这项工作,因为你需要一个声明为weak var的财产,并且对weak var接受哪些类型有限制 - 基本上它们是AnyObject

+1

至于选项2:在这里,'class'和'AnyObject'没有相同的效果吗?当我尝试它时似乎没有什么区别。至于选项4:据我所知,从AnyObject继承是使泛型类绑定的唯一方法。你能否提供选项2和4的示例实现? – Theo

0

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

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 
      } 
     } 
    } 
} 
+0

这不能用swift编译3 –

1

如果您的协议可以被标记为@obj,那么你可以在下面

protocol Observerable { 

    associatedtype P : AnyObject 

    var delegates: NSHashTable<P> { get } 
} 

@objc protocol MyProtocol { 

    func someFunc() 

} 

class SomeClass : Observerable { 

    var delegates = NSHashTable<MyProtocol>.weakObjects() 

} 
相关问题