Reputation: 111
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
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
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