jad6os jad6os - 4 months ago 12
Swift Question

Extending Protocols conforming to NSFetchRequestResult

I am migrating my code to Swift 3 and I ran into an issue that I am not 100% sure about.

As of WWDC 2016 the Core Data team updated their framework to be friendlier to generics and the new beefed up

NSFetchRequest
now returns objects that conform to the
NSFetchRequestResult
.

So in the code below I have my base protocol that conforms to the said
NSFetchRequestResult
protocol, and in an extension of its child protocol
ManagedObjectFetchable
I want to return fetch objects of conforming types:

import CoreData

@objc protocol ManagedObjectType: class, NSFetchRequestResult { }

protocol ManagedObjectFetchable: ManagedObjectType { }

extension ManagedObjectFetchable {
static func preFetch(for predicate: Predicate, sortedBy sortDescriptors: [SortDescriptor]) throws -> [Self] {
let fetchRequest = NSFetchRequest<Self>(entityName: Self.entityName)
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = sortDescriptors

let dummyContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
return try dummyContext.fetch(fetchRequest)
}
}


The problem here is this line:

// Error: Binary operator '<' cannot be applied to operands of type 'NSFetchRequest<_>.Type' and 'Self.Type'
let fetchRequest = NSFetchRequest<Self>(entityName: Self.entityName)


It is a little confusing because I don't think this has anything to do with binary operators... Before I jump to the all too easy conclusion that it is a Swift bug I was wondering if anyone ran into similar issues.




I am able to get around this using generics:

extension ManagedObjectFetchable {
static func preFetch<T: ManagedObjectFetchable>(for predicate: Predicate, sortedBy sortDescriptors: [SortDescriptor]) throws -> [T] {
let fetchRequest = NSFetchRequest<T>(entityName: Self.entityName)
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = sortDescriptors

let dummyContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
return try dummyContext.fetch(fetchRequest)
}
}


This is what I am going with for now but I don't like not understanding why this would not work. If anyone could help enlighten this problem that would be awesome!

Answer

This is a bug in Swift. Change:

let fetchRequest = NSFetchRequest<Self>(entityName: Self.entityName)

to:

let fetchRequest: NSFetchRequest<Self> = NSFetchRequest(entityName: Self.entityName)

and the code should compile.