Einmannbude
Einmannbude

Reputation: 53

How to cast to generic type in Swift

I am about to learn Swift. I want to write a class, that handles Cora Data tasks for me. In this case, it should be possible to pass an entity name and and array of tuples to a function, which then interprets the tuples as key value pairs for NSPredicates to retrieve ManagedObjects matching them. Because of NSPredicate needing values with specific types, I tried to pass the types of the values, too. But I can't get around that "'t' is not a type" compile error (last line of code). How can I cast the value to an passed type? Or would you create the NSPredicate in a totally different way?

class func getManagedObjectsWithEntityName<T>(entityName: String, keysAndValues: [(key: String, value: AnyObject, type: T.Type)]) -> [NSManagedObject] {

    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext

    let fetchRequest = NSFetchRequest(entityName: entityName)
    var predicates: [NSPredicate] = []

    for tuple in keysAndValues {
        let t = tuple.type
        predicates.append( NSPredicate(format: tuple.key + " = %@", tuple.value as t)!)
    }

    ...
}

Upvotes: 0

Views: 774

Answers (1)

James Alvarez
James Alvarez

Reputation: 7219

No need to use generics here, you don't seem to need to have to access any of the members / functions of whatever class you would use as a generic.

What you do have however is a choice: either you can take values as conforming to CVarArgType, allowing you to plug them straight into your NSPredicate constructor, or you can take values as strings and construct the predicate by building a string expression. Here is an example using CVarArgType:

func getManagedObjectsWithEntityName(entityName: String, keysAndValues: 
    [(key: String, value: CVarArgType)]) -> [NSManagedObject] {

    ...

    let fetchRequest = NSFetchRequest(entityName: entityName)
    var predicates: [NSPredicate] = []

    for tuple in keysAndValues {
        predicates.append( NSPredicate(format: "%K = %@", tuple.key, tuple.value))
    }

    ...

}

The reason your generic wasn't working is that you set up a place holder , but then your tuple.type in the function sig was actually T.Type (rather than just T). If you changed the tuple specification to (key: String, value: AnyObject, type: T) then you would be able to cast let t = tuple.type as! T. But then you would run into problems as NSPredicate doesn't take type T - whence the solution not really being to use generics, but instead use something like the above. It's also worth bearing in mind it's a good idea to avoid using variable names such as .type and .value, as in certain cases these will cause confusion with things, especially with NSManagedObjects (which have .value). At least it's worth knowing that this can be a cause of issues...

Upvotes: 1

Related Questions