I am trying to implement a structure that allows me to store a set of weak observers.
Here is the observer wrapper:
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
}
}
And here is the protocol every observer needs to conform to:
public protocol DataModelObserverProtocol : class, Hashable, AnyObject {
func someFunc()
}
Usage:
public class DataModel: NSObject, DataModelInterface {
public var observers = Set<WeakObserver<DataModelObserverProtocol>>()
//^^^^^ Using 'DataModelObserverProtocol' as a concrete type conforming to protocol 'AnyObject' is not supported
}
Now, while I am aware that this might be a limitation by Swift itself, I am looking for an alternative solution without having a concrete class as type constraint (if that's not possible, which I am afraid is the case, I'd still love to get alternative "non-hacky" solutions).
Using a Set to hold the references runs a risk that the Set will eventually need to reference an element using its hashValue and, when the weak reference goes nil, the hashValue function will crash.
I couldn't do it with protocols but I found a way to get a similar functionality using a generic function that returns a tuple of functions.
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)
}
To add observers, you would use:
observers.addObject( yourObserver )
To iterate through the observers :
for observer in observers.objects()
{
observer.someFunc()
}
Both functions are type safe and will only accept/return DataModelObserverProtocol compliant objects
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With