2015-09-27 41 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() 

} 
相關問題