I've been surprised by the change of behavior of moving a class into its module and observing a behavior change in this container behavior.
The container is this one
public struct WeakObserverOrderedSet<T> {
public struct Weak {
// using dynamic cast because i couldn't find a way to code a generic Weak container
// over a protocol
weak var value: AnyObject?
init(_ v: AnyObject) {
value = v
}
}
var elements: [Weak] = []
public mutating func add(value: T) {
let anyValue = value as AnyObject
guard indexOf(value: anyValue) == nil else { return }
elements.append(Weak(anyValue))
}
// …
public func invoke(_ f: ((T) throws -> Void)) rethrows {
for e in elements {
guard let val = e.value else { continue }
if let eVal = e.value as? T {
try f(eVal)
} else {
print("could not cast \(e.value) as \(T.self)")
}
}
}
It's usually used with protocol type such as :
protocol MyClassObserver: AnyObject { func onThis() }
class MyClass {
var observers: WeakObserverOrderedSet<MyClassObserver>
}
and its goal is to implement some kind of multicast delegate over any protocol.
The code was working fine, until i started using it across modules. In some configuration, a component that was defined in module A could register itself as an observer to a component defined in module B, using the "componentB.observers.add(self)", but the "invoke" method failed at the dynamic casting.
I've read about the issue with retroactive protocol conformance, however this isn't the case here. The component in module A is defined publicly as conforming to the B protocol. It's just that module B doesn't know about module A or its types.
The two questions are : why isn't this working, and how to make this work ?