Georg Kitz
Georg Kitz

Reputation: 111

Default implementation of protocol extension in Swift not working

I'm trying to add functionality to an NSManagedObject via a protocol. I added a default implementation which works fine, but as soon as I try to extend my subclass with the protocol it tells me that parts of it are not implemented, even though I added the default implementation.

Anyone having Ideas of what I'm doing wrong?

class Case: NSManagedObject {

}

protocol ObjectByIdFetchable {
    typealias T
    typealias I
    static var idName: String { get }
    static func entityName() -> String
    static func objectWithId(ids:[I], context: NSManagedObjectContext) -> [T]
}

extension ObjectByIdFetchable where T: NSManagedObject, I: AnyObject {

    static func objectWithId(ids:[I], context: NSManagedObjectContext) -> [T] {
       let r = NSFetchRequest(entityName: self.entityName())
       r.predicate = NSPredicate(format: "%K IN %@", idName, ids)

       return context.typedFetchRequest(r)
   }
}

extension Case: ObjectByIdFetchable {

   typealias T = Case
   typealias I = Int

   class var idName: String {
       return "id"
   }

   override class func entityName() -> String {
       return "Case"
   }
}

The error I get is Type Case doesn't conform to protocol ObjectByIdFetchable

Help very much appreciated.

Upvotes: 0

Views: 2729

Answers (2)

dfrib
dfrib

Reputation: 73166

We'll use a more scaled-down example (below) to shed light on what goes wrong here. The key "error", however, is that Case cannot make use of the default implementation of objectWithId() for ... where T: NSManagedObject, I: AnyObject; since type Int does not conform to the type constraint AnyObject. The latter is used to represent instances of class types, whereas Int is a value type.

AnyObject can represent an instance of any class type.

Any can represent an instance of any type at all, including function types.

From the Language Guide - Type casting.

Subsequently, Case does not have access to any implementation of the blueprinted objectWithId() method, and does hence not conform to protocol ObjectByIdFetchable.


Default extension of Foo to T:s conforming to Any works, since Int conforms to Any:

protocol Foo {
    typealias T
    static func bar()
    static func baz()
}

extension Foo where T: Any {
    static func bar() { print ("bar") }
}

class Case : Foo {
    typealias T = Int

    class func baz() {
        print("baz")
    }
}

The same is, however, not true for extending Foo to T:s conforming to AnyObject, as Int does not conform to the class-type general AnyObject:

protocol Foo {
    typealias T
    static func bar()
    static func baz()
}

/* This will not be usable by Case below */
extension Foo where T: AnyObject {
    static func bar() { print ("bar") }
}

/* Hence, Case does not conform to Foo, as it contains no
   implementation for the blueprinted method bar()    */
class Case : Foo {
    typealias T = Int

    class func baz() {
        print("baz")
    }
}

Edit addition: note that if you change (as you've posted in you own answer)

typealias T = Int

into

typealias T = NSNumber

then naturally Case has access to the default implementation of objectWithId() for ... where T: NSManagedObject, I: AnyObject, as NSNumber is class type, which conforms to AnyObject.


Finally, note from the examples above that the keyword override is not needed for implementing methods blueprinted in a protocol (e.g., entityName() method in your example above). The extension of Case is an protocol extension (conforming to ObjectByIdFetchable by implementing blueprinted types and methods), and not really comparable to subclassing Case by a superclass (in which case you might want to override superclass methods).

Upvotes: 4

Georg Kitz
Georg Kitz

Reputation: 111

I found the solution to the problem. I thought it's the typealias T which is the reason for not compiling. That's actually not true, it's I which I said to AnyObject, the interesting thing is that Int is not AnyObject. I had to change Int to NSNumber

Upvotes: 0

Related Questions