Set containing weak pointers

Aim:

I am trying to create a Set containing weak pointers conforming to a protocol

My Attempt:

  • I have a crude version of it, shown below.

Questions:

  1. Is there a way to make it generic? (when I tried to I did encounter the error Value of protocol type 'P1' cannot conform to 'P1'; only struct/enum/class types can conform to protocols)
  2. Is there a better way to handle the hashing function? Or is my hashing function ok?
  3. Is there a better solution?

Code:

protocol P1 : AnyObject {
    func f1()
}

struct WeakP1 : Equatable, Hashable {
 
    weak var pointer : P1?

    static func == (lhs: WeakP1, rhs: WeakP1) -> Bool {
        lhs.pointer === rhs.pointer
    }
    
    func hash(into hasher: inout Hasher) {
        if let pointer = pointer {
            hasher.combine(ObjectIdentifier(pointer))
        } else {
            hasher.combine("")
        }
    }
}

class Car : P1 {
    func f1() {
        print("car")
    }
}
class Bike : P1 {
    func f1() {
        print("bike")
    }
}

var c1 : Car? = Car()
let c2 = Car()
let b1 = Bike()

var set = Set<WeakP1>()

set.insert(WeakP1(pointer: c1))
set.insert(WeakP1(pointer: b1))
set.insert(WeakP1(pointer: c2))
set.insert(WeakP1(pointer: c1))
  1. Try WeakP1WeakP1<Value: P1> and pointer : P1?pointer : Value?
  2. I'm pretty sure current solution is UB: think what happens when pointer of multiple WeakP1 instances gets deallocated after they are added to the set
  3. Depends on how you want to handle [2], but Set-like collections don't seem to fit the usecase
1 Like

See Hashing Weak Variables.

I ended up using associated objects as a hand-made side table.

1 Like

@Kentzo @Nickolas_Pohilets, thanks for those suggestions.

The implementation seemed more complicated than what I initially thought.

I decided I would use protocol extensions to provide a default implementation that the class / struct can use that way I didn't need to build a set containing weak references.