2016-01-16 70 views
4

弱觀察員我想實現的結構,讓我來存儲一組弱觀察員。坐落在斯威夫特

這裏是觀察包裝:

public func ==<T: Hashable>(lhs: WeakObserver<T>, rhs: WeakObserver<T>) -> Bool { 
    return lhs.hashValue == rhs.hashValue 
} 

public struct WeakObserver<T where T: AnyObject, T: Hashable> : Hashable { 

    private weak var weakObserver : T? 

    public init(weakObserver: T){ 
    self.weakObserver = weakObserver 
    } 

    public var hashValue : Int { 
    return self.weakObserver!.hashValue 
    } 

} 

這裏是每一個觀察者需要符合協議:

public protocol DataModelObserverProtocol : class, Hashable, AnyObject { 

    func someFunc() 

} 

用法:

public class DataModel: NSObject, DataModelInterface { 

    public var observers = Set<WeakObserver<DataModelObserverProtocol>>() 
    //^^^^^ Using 'DataModelObserverProtocol' as a concrete type conforming to protocol 'AnyObject' is not supported 
} 

現在,當我意識到這可能是Swift本身的限制,我正在尋找一種替代解決方案,而不需要具體的cl屁股作爲類型約束(如果這是不可能的,我恐怕是這種情況,我仍然喜歡得到替代的「非哈克」解決方案)。

+1

它的價值檢查https://gist.github.com/preble/13ab713ac044876c89b5 – Kirsteins

+0

@Kirsteins這實際上看起來非常像我要找的東西,但它也看起來有點矯枉過正(沒有明顯的原因) –

+1

@Kirsteins即使使用'WeakSet',我也會得到'使用協議作爲符合協議的具體類型'的錯誤。 –

回答

0

我知道會有這樣做的更好的方法,但它只是似乎s到是這樣一個簡單的概念太複雜了,所以我就用不同的方式:

我只是用NSNotificationCenter和重構我的代碼不是必須有一個緊耦合結構,所以不是從通知傳遞信息,我設法以一種對我有用的方式來抽象它,通知不需要向觀察者傳遞參數。由於通知只支持通過userInfo字典傳遞信息,所以我不得不考慮這一點。

所以正如我所說,我需要做的背景下解耦方法。 這是一個非常抽象的答案,但我認爲這可能有助於避免不必要弄亂「功能失常的泛型」的問題。

要通知我觀察我只是註冊他們:

NSNotificationCenter.defaultCenter().addObserver(...) 

和後通知無參數:

NSNotificationCenter.defaultCenter().postNotification... 

我已經使用了內置在以前的項目NSNotificationCenter,我完全知道其內部運作的,但我本來將信息傳遞下來的觀察員,這也是我爲什麼要限制多一點創造各種各樣的WeakSet

同樣,這曾在我的情況,因爲我的觀察不一定需要獲得通過的可觀察的細節,因爲它通常存在,並且通過反正觀察員訪問(這事我結構提供,它可能不是以這種方式讀者的案例)。這很難解釋它,所以任何人都讀這篇文章是有道理的,但是我被建議的WeakSet非常沮喪,所以我就這樣做了。它更具可讀性(儘管第三方可能不那麼容易理解),而且這對我的用例來說似乎更合適。

2

使用集來存放引用運行的風險,即設置最終將需要參考使用其散列值,而當弱引用變爲零,該散列值函數會崩潰的元素。

我不能協議做,但我發現了一個辦法讓類似的功能使用返回函數的元組的通用功能。

struct WeakReference<T> 
{ 
    weak var _reference:AnyObject? 
    init(_ object:T) {_reference = object as? AnyObject} 
    var reference:T? { return _reference as? T } 
} 

func weakReferences<T>(_:T.Type) -> ( 
            getObjects:()->[T], 
            addObject: (T)->() 
            ) 
{ 
    var references : [WeakReference<T>] = [] 

    func getObjects() -> [T] 
    { 
     return references.filter({ $0.reference != nil }).map({$0.reference!}) 
    } 

    func addObject(object:T) 
    { 
     if getObjects().contains({ ($0 as! AnyObject) === (object as! AnyObject) }) 
     { return } 
     references.append(WeakReference(object)) 
    } 

    return (getObjects:getObjects, addObject:addObject) 
} 

public protocol DataModelObserverProtocol: class, AnyObject 
{ 
    func someFunc() -> String 
} 

public class DataModel: NSObject, DataModelInterface 
{ 
    var observers = weakReferences(DataModelObserverProtocol) 
} 

要添加觀察員,你可以使用:

observers.addObject(yourObserver) 

要通過觀察迭代:

for observer in observers.objects() 
{ 
    observer.someFunc() 
} 

兩個功能型安全,將只接受/返回DataModelObserverProtocol柔軟物體

+0

'WeakReference'中的類型轉換會影響性能嗎? – kelin

+0

這種類型轉換在編譯時處理,僅告訴編譯器我們知道變量是兼容類型。 –

+0

唯一的開銷是函數調用中存儲器和一個間接尋址的一些額外「單詞」。這對性能不太可能有任何有意義的影響。 –