Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

221
Visualizações
How can I design a generic observer pattern protocol in Swift?

I want to design a generic Swift protocol for the observer pattern for use with different types/classes. The problem is that I can't seem to specify the type for the observer's notify() method.

Initially, I tried creating an associatedtype with my Observer protocol.

protocol Observer {
    associatedtype T
    func notify(_ value: T)
}

protocol Observable {
    var observers: [Observer] { get set }
    func registerObserver(_ observer: Observer)
    func unregisterObserver(_ observer: Observer)
}

This doesn't work (compilation error): error: protocol 'Observer' can only be used as a generic constraint because it has Self or associated type requirements.

So I tried using generic methods instead:

protocol Observer {
    func notify<T>(_ value: T)
}

protocol Observable {
    associatedtype T
    var observers: [Observer] { get set } // This is okay now
}

extension Observable {
    // implement registerObserver()
    // implement unregisterObserver()

    func notifyObservers<T>(_ value: T) {
        for observer in observers {
            observer.notify(value)
        }
    }
}

This works just fine, but leads to some pretty interesting result. To test it out, I created FooObserver and FooObservable:

class FooObserver: Observer {
    func notify<T>(_ value: T) {
        print(value)
    }
}

class FooObservable: Observable {
    typealias T = Int // For simplicity I set T to Int type
    var observers: [Observer] = []
}

let a = FooObserver()
let b = FooObserver()
var c = FooObservable()
c.registerObserver(a)
c.registerObserver(b)
c.notifyObservers("hello") // This works, but why?

I was able to successfully notify my 2 observers of the string "hello". I'm guessing this has to do with type erasure...?

So my question is: how can I implement a generic-type observer pattern where I can be sure that the value in notify() is of the correct type?

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

protocol Observer {
    associatedtype T
    func notify(_ value: T)
}

This says that a given observer can handle one specific type (T) that the observer chooses.

protocol Observable {
    var observers: [Observer] { get set }
    func registerObserver(_ observer: Observer)
    func unregisterObserver(_ observer: Observer)
}

This is invalid, because the system has no way to know what T you want for these observers. Each observer can only handle exactly one T.

protocol Observer {
    func notify<T>(_ value: T)
}

This is basically meaningless. It says that notify can be called with any type at all. If that's what you mean, you want to say:

protocol Observer {
    func notify(_ value: Any)
}

But that means that every observer has to deal with Any, which is not good. The reason it happens to work is that you chose print as your test. print can handle Any. When you want to test these kinds of things, you need to try something like what you really want to do in your program. Printing works for all kinds of things that are useless for any other purpose.

The basic problem is that Observer shouldn't be a protocol. It should be a function. For example:

typealias Observer<T> = (T) -> Void

protocol Observable {
    associatedtype T
    var observers: [Observer<T>] { get set }
    func registerObserver(_ observer: Observer<T>)
    func unregisterObserver(_ observer: Observer<T>)
}

The problem with this approach is there's no way to implement unregisterObserver. I'm not clear how you've implemented unregisterObserver in your code, either. It doesn't really look possible.

Here's one very simple way to build an observable:

typealias Observer<T> = (T) -> ()

struct Subscription {
    let cancel: () -> Void
}

final class Observable<T> {
    private var observations: [UUID: Observer<T>] = [:]
    func subscribe(observer: @escaping Observer<T>) -> Subscription {
        let uuid = UUID()
        observations[uuid] = observer
        return Subscription(cancel: { [weak self] in self?.observations[uuid] = nil })
    }
}

(See https://stackoverflow.com/a/55389143/97337 for where this comes from.)

For a more fully worked out version that is very simple, see Observable. For a somewhat more complicated version that is a little quirky, see Stream. For a more powerful and less quirky version, see Properties. For a very powerful version that establishes a whole way of programming, see RxSwift.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda