Home > Blockchain >  Add object to an array that confirm to the protocol that has associated type in it
Add object to an array that confirm to the protocol that has associated type in it

Time:01-28

I have problem to write the code that puts objects into the observers array. The objects implement the Observer protocol. I would like to link the ValueType with the generic type T of the Subject. Here is the code that shows what I want to do:

protocol Observer {
    associatedtype ValueType
    func update(value: ValueType)
}

struct Subject<T> {
    private var observers = Array<Observer>()

    mutating func attach(observer: Observer) {
        observers.append(observer)
    }

    func notyfi(value: T) {
        for observer in observers {
            observer.update(value: value)
        }
    }
}

CodePudding user response:

If your deployment target is at least a late 2022 release (iOS 16, macOS 13, etc.), you can use a constrained existential:

protocol Observer<ValueType> {
    associatedtype ValueType
    func update(value: ValueType)
}

struct Subject<T> {
    private var observers = Array<any Observer<T>>()

    mutating func attach(observer: any Observer<T>) {
        observers.append(observer)
    }

    func notify(value: T) {
        for observer in observers {
            observer.update(value: value)
        }
    }
}

If your deployment target is earlier, the Swift runtime doesn't support constrained existentials. (From SE-0353: “It is worth noting that this feature requires revisions to the Swift runtime and ABI that are not backwards-compatible nor backwards-deployable to existing OS releases.”) But you can use closures instead:

protocol Observer<ValueType> {
    associatedtype ValueType
    func update(value: ValueType)
}

struct Subject<T> {
    private var observers: [(T) -> Void] = []
    
    mutating func attach<O: Observer>(observer: O)
    where O.ValueType == T
    {
        observers.append { observer.update(value: $0) }
    }

    func notify(value: T) {
        for observer in observers {
            observer(value)
        }
    }
}

CodePudding user response:

Why don't you use the Observer as the generic parameter?

struct Subject<O: Observer> {

    typealias T = O.ValueType

    private var observers = Array<O>()

    mutating func attach(observer: O) {
        observers.append(observer)
    }

    func notyfi(value: T) {
        for observer in observers {
            observer.update(value: value)
        }
    }
}
  • Related