I'm trying to create a generic WeakReference
type that I can put into an array (and ultimately create a generic weak array type).
So far so good, but the following code:
class WeakReference<ElementType: AnyObject> {
weak var element: ElementType?
init(_ element: ElementType) {
self.element = element
}
}
protocol Element: AnyObject {}
class WeakElementHolder {
var weakElements: [WeakReference<Element>] = []
}
Produces this compiler error:
WeakReference.swift:12:21: error: 'WeakReference' requires that 'Element' be a class type
var weakElements: [WeakReference<Element>] = []
^
WeakReference.swift:1:7: note: requirement specified as 'ElementType' : 'AnyObject' [with ElementType = Element]
class WeakReference<ElementType: AnyObject> {
^
This is strange because the Protocol definitely requires a class (AnyObject
).
Strangely everything works fine if I leave out the generics:
protocol Element: AnyObject {}
class WeakElementReference {
weak var element: Element?
init(_ element: Element) {
self.element = element
}
}
class WeakElementHolder {
var weakElements: [WeakElementReference] = []
}
Searching around I found this question but it wasn't really answered.
Is there a workaround to still somehow implement a generic array of weak references that works with class bound protocols?
UPDATE:
My concrete use case is to store a list of observers that get notified when something happens:
protocol Observer: AnyObject {
func notify()
}
class WeakReference<ElementType: AnyObject> {
weak var element: ElementType?
init(_ element: ElementType) {
self.element = element
}
}
class WeakArray<ElementType: AnyObject> {
var content: [WeakReference<ElementType>] = []
}
class Observable {
var observers: WeakArray<Observer>()
func notifyAllObservers() {
// call notify() on all observers here
}
}
These observers can be many different concrete types.
More Clarification:
There is not only one Observer
protocol, there are many that have nothing in common, this is why I want this to be generic in the first place.
As discussed in Protocol doesn't conform to itself?, the (non-@objc
) protocol defined by
protocol Element: AnyObject {}
inherits from AnyObject
, but does not conform to AnyObject
.
A possible solution using a type-eraser:
protocol Observer: AnyObject {
func notify()
}
struct AnyObserver {
weak var base: Observer?
init(_ base: Observer ) {
self.base = base
}
}
class Observable {
var observers: [AnyObserver] = []
func add(_ observer: Observer) {
observers.append(AnyObserver(observer))
}
func notifyAllObservers() {
for observer in observers {
observer.base?.notify()
}
}
}
Example usage:
class A: Observer {
func notify() {
print("Hello A")
}
}
class B: Observer {
func notify() {
print("Hello B")
}
}
let a = A()
let b = B()
let o = Observable()
o.add(a)
o.add(b)
o.notifyAllObservers()
// Hello A
// Hello B
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