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

167
Visualizações
Observing a list of Swift KeyPaths

I have the following code which adds an observer on two properties:

    obs = []

    let xa = self.observe(\CirclePolygon.radius, options: [.new]) { (op, ch) in
        callback()
    }
    obs.append(xa)


    let xb = self.observe(\CirclePolygon.origin.x, options: [.new]) { (op, ch) in
        callback()
    }
    obs.append(xb)

It works, but I don't like the duplciation. I have tried to pass a list of KeyPaths:

    obs = []

    let keyPaths = [\CirclePolygon.radius, \CirclePolygon.origin.x]
    for keyPath in keyPaths {
        let xa = self.observe(keyPath, options: [.new]) { (op, ch) in
            callback()
        }
        obs.append(xa)
    }

But I get the compiler error: Generic parameter 'Value' could not be inferred

Is there anyway to do this?

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

0

First of all, remember that KVO only works on instances of NSObject (or a subclass). So if the origin property of CirclePolygon is a CGPoint or some other struct, you'll get a run-time error when you try to register an observer of \CirclePolygon.origin.x, because KVO cannot apply to the x property of a CGPoint.

Second, the key paths you gave have different types. Let's say (to address my first point) you want to observe radius (a Double) and origin (a CGPoint). The key paths have different types:

\CirclePolygon.radius   // type: KeyPath<CirclePolygon, Double>
\CirclePolygon.origin   // type: KeyPath<CirclePolygon, CGPoint>

If you try to put these in a single array, without explicitly specifying the type of the array, Swift will deduce it as follows:

let keyPaths = [\CirclePolygon.origin, \CirclePolygon.radius]
// deduced type of keyPaths: [PartialKeyPath<CirclePolygon>]

It deduces [PartialKeyPath<CirclePolygon>] because PartialKeyPath<CirclePolygon> is the nearest common ancestor of both KeyPath<CirclePolygon, Double> and KeyPath<CirclePolygon, CGPoint>.

So, in the for loop where you iterate over the array, you're passing an object with static type PartialKeyPath<CirclePolygon> as the keyPath argument of the observe(_:options:changeHandler:) method. Unfortunately, that method is declared as follows:

public func observe<Value>(
        _ keyPath: KeyPath<Self, Value>,
        options: NSKeyValueObservingOptions = [],
        changeHandler: @escaping (Self, NSKeyValueObservedChange<Value>) -> Void)
    -> NSKeyValueObservation

Which is to say, the method requires a KeyPath<Self, Value> but you're passing a PartialKeyPath<Self>, so Swift emits an error. As is often the case with Swift errors around generic type problems, the error isn't very helpful.

You cannot solve this problem by casting, because you cannot (for example) cast KeyPath<CirclePolygon, Double> to KeyPath<CirclePolygon, Any>.

One solution may be to use a local function to encapsulate the common code, like this:

func register(callback: @escaping () -> ()) -> [NSKeyValueObservation] {
    func r<Value>(_ keyPath: KeyPath<CirclePolygon, Value>) -> NSKeyValueObservation {
        return observe(keyPath, options: []) { (_, _) in
            callback()
        }
    }

    return [
        r(\.radius),
        r(\.origin),
    ]
}
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