Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic parameter 'Value' could not be inferred creating block based KVO in swift

Entering this (contrived example) code

import Foundation

protocol ValueProviderProtocol {
    var amount: Int { get }
}

class ValueProvider: NSObject, ValueProviderProtocol {
    @objc dynamic var amount = 0
}

let _provider = ValueProvider()

var provider: ValueProviderProtocol { return _provider }

let subject = provider as! NSObject

let observer = subject.observe(\ValueProviderProtocol.amount, options: [.old, .new]) { (provider, changes) in

}

into an Xcode 9 playground, results in this error for the call to subject.observe:

Generic parameter 'Value' could not be inferred

It is not clear what is causing the error. What can be done to fix this kind of problem?

like image 745
Tron Thomas Avatar asked Nov 03 '17 02:11

Tron Thomas


People also ask

What is a type parameter in Swift?

These type parameters act as placeholders that are replaced by actual concrete type arguments when an instance of a generic type is created or a generic function or initializer is called. For an overview of generics in Swift, see Generics.

Why can't the generic function infer the type of <T>?

The generic function could not infer the type of <T> from the calling function. Fair enough, as my calling function does not provide the type <T> because the generic function (the function being called) did not have a parameter (or any other way) to specify type <T>.

Can a generic where clause be substituted for a type parameter?

Any type argument substituted for a type parameter must meet all the constraints and requirements placed on the type parameter. A generic where clause can appear as part of a declaration that includes type parameters, or as part of a declaration that’s nested inside of a declaration that includes type parameters.

What is a generic parameter list?

The generic parameter list is a comma-separated list of generic parameters, each of which has the following form: A generic parameter consists of a type parameter followed by an optional constraint. A type parameter is simply the name of a placeholder type (for instance, T, U, V, Key, Value, and so on).


1 Answers

The following line:

let observer = subject.observe(\ValueProviderProtocol.amount, 
                               options: [.old, .new])
                               { (provider, changes) in
}

needs to change in to:

let observer = _provider.observe(\.amount,
                                 options: [.old, .new],
                                 changeHandler: { (provider, changes) in

})

You can not try to observe on subject since is downcasted to an NSObject that does not have the property amount. And second \ValueProviderProtocol.amount is a partial key path that does not infere value type \.amount is a KeyPath that inferes keypath

like image 112
moglistree Avatar answered Dec 03 '22 22:12

moglistree