So the problem seems to be, that the compiler needs to infer the type of T somehow. But it isn't allowed to simply use generic< type >(params...).
Normally, the compiler can look for the type of T, by scanning the parameter types because this is where T is used in many cases.
In my case it was a little bit different, because the return type of my function was T. In your case it seems that you haven't used T at all in your function. I guess you just simplified the example code.
So I have the following function
func getProperty<T>( propertyID : String ) -> T
And in case of, for instance
getProperty<Int>("countProperty")
the compiler gives me the error:
Cannot explicitly specialize a generic function
So, to give the compiler another source of information to infer the type of T from, you have to explicitly declare the type of the variable the return value is saved in.
var value : Int = getProperty("countProperty")
This way the compiler knows that T has to be an integer.
So I think overall it simply means that if you specify a generic function you have to at least use T in your parameter types or as a return type.
You don't need a generic here since you have static types (String as parameter), but if you want to have a generic function call another you could do the following.
Using Generic methods
func fetchObjectOrCreate<T: NSManagedObject>(type: T.Type) -> T {
if let existing = fetchExisting(type) {
return existing
}
else {
return createNew(type)
}
}
func fetchExisting<T: NSManagedObject>(type: T.Type) -> T {
let entityName = NSStringFromClass(type)
// Run query for entiry
}
func createNew<T: NSManagedObject>(type: T.Type) -> T {
let entityName = NSStringFromClass(type)
// create entity with name
}
Using a generic class (Less flexible as the generic can be defined for 1 type only per instance)
class Foo<T> {
func doStuff(text: String) -> T {
return doOtherStuff(text)
}
func doOtherStuff(text: String) -> T {
}
}
let foo = Foo<Int>()
foo.doStuff("text")
I had a similar problem with my generic class function class func retrieveByKey<T: GrandLite>(key: String) -> T?.
I could not call it let a = retrieveByKey<Categories>(key: "abc") where Categories is a subclass of GrandLite.
let a = Categories.retrieveByKey(key:"abc") returned GrandLite, not Categories. Generic functions do not infer type based on the class that calls them.
class func retrieveByKey<T: GrandLite>(aType: T, key: String>) -> T? gave me an error when I tried let a = Categories.retrieveByKey(aType: Categories, key: "abc") gave me an error that it could not convert Categories.Type to GrandLite, even though Categories is a subclass of GrandLite. HOWEVER...
class func retrieveByKey<T: GrandLite>(aType: [T], key: String) -> T?did work if I tried let a = Categories.retrieveByKey(aType: [Categories](), key: "abc") apparently an explicit assignment of a subclass does not work, but an implicit assigment using another generic type (array) does work in Swift 3.
Typically there are many ways to define generic functions. But they are based on condition that T must be used as a parameter, or as a return type.
extension UIViewController {
class func doSomething<T: UIView>() -> T {
return T()
}
class func doSomethingElse<T: UIView>(value: T) {
// Note: value is a instance of T
}
class func doLastThing<T: UIView>(value: T.Type) {
// Note: value is a MetaType of T
}
}
After that, we must provide T when calling.
let result = UIViewController.doSomething() as UIImageView // Define `T` by casting, as UIImageView
let result: UILabel = UIViewController.doSomething() // Define `T` with property type, as UILabel
UIViewController.doSomethingElse(value: UIButton()) // Define `T` with parameter type, as UIButton
UIViewController.doLastThing(value: UITextView.self) // Define `T` with parameter type, as UITextView
So far, my personal best practise used @orkhan-alikhanov 's answer. Today, when looking at SwiftUI and how .modifier() and the ViewModifier is implemented, I found another way (or is it more a workaround?)
Simply wrap the second function into a struct.
Example:
If this one gives you the "Cannot explicitly specialize a generic function"
I don't know if it helps in any possible case, when this error message occurs. I just know, that I was stuck many times when this came up. I do know, that this solution helped today, when the error-message came up.
The way Swift handles Generics is for me still confusing.
This example and the workaround with the struct is a good example. The workaround here has not a bit more information - but passes the compiler. Same information, but different results? Then something is wrong. If it is a compiler-bug it can get fixed.