It seems that Swift generics work fine, as long as I don't try to combine them in any practical way. I'm using Swift 4.1, and I would like to create a generic array containing only weak references. I can define this as WeakList<T>. So far so well. But: I would like to use a protocol for T. Swift says nope..
import Foundation
protocol Observer: class {
func stateChanged(sender: SomeClass, newState: Int)
}
struct WeakList<T> where T: AnyObject {
struct Ptr {
weak var p: T?
}
private var storage: [Ptr] = []
var aliveObjects: [T] {
var result: [T] = []
for ptr in storage {
if let p = ptr.p {
result.append(p)
}
}
return result
}
mutating func add(_ obj: T) {
storage.append(Ptr(p: obj))
}
// Let's ignore for a moment that this implementation leaks memory badly.
}
class SomeClass {
var someVar: WeakList<Observer> = WeakList<Observer>()
// Error: WeakList requires that 'Observer' be a class type
var thisIsOk: WeakList<NSObject> = WeakList<NSObject>()
}
(this is not my original code but a minimal verifyable example that contains enough details so that no one can say "just remove the AnyObject constraint from the structure")
I guess what I'm trying to do is just not possible. Or is it? It's just frustrating how 4 out of 5 times when I try to do something with Swift generics, I later learn that what I am trying to do is just not possible. (I can implement the same thing in Objective-C easily, by the way.)
class constraint to an AnyObject constraint => doesn't work either.AnyObject constraint to a class constraint => doesn't even compile.protocol Observer where Self: NSObject doesn't change anything. NSObject is a class type, Observer is an NSObject. It should follow that Observer is a class type. The "is a" relationship doesn't seem to be transitive here.With current implementation you cannot inherit the protocol from AnyObject. What you can do is to create a Type Eraser for your protocol and use that instead. Now your type eraser can be inherited from AnyObject.
Something like this:
protocol Observer {
func stateChanged(sender: SomeClass, newState: Int)
}
class AnyObserver: NSObject, Observer {
private let observer: Observer
init(observer: Observer) {
self.observer = observer
}
func stateChanged(sender: SomeClass, newState: Int) {
observer.stateChanged(sender: sender, newState: newState)
}
}
struct WeakList<T> where T: AnyObject {
struct Ptr {
weak var p: T?
}
private var storage: [Ptr] = []
var aliveObjects: [T] {
var result: [T] = []
for ptr in storage {
if let p = ptr.p {
result.append(p)
}
}
return result
}
mutating func add(_ obj: T) {
storage.append(Ptr(p: obj))
}
// Let's ignore for a moment that this implementation leaks memory badly.
}
class SomeClass {
var someVar: WeakList<AnyObserver> = WeakList<AnyObserver>()
var thisIsOk: WeakList<NSObject> = WeakList<NSObject>()
}
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