2

I have this protocol:

protocol ManagedObjectProtocol {
    associatedtype Entity
    
    static var identifierKey: String { get }
    static func fetchRequest() -> NSFetchRequest<NSFetchRequestResult>
    
    func toEntity() -> Entity?
}

I confirm to some of my NSManagedObject classes with extension like this:

extension AppEntity: ManagedObjectProtocol {
    typealias Entity = App
    
    static var identifierKey: String {
        return "articleId"
    }
    
    func toEntity() -> Entity? {
        return nil
    }
}

When I try to archive with new Xcode 13 I get this error:

Type 'AppEntity' does not conform to protocol 'ManagedObjectProtocol'

But when I just try to run this code on my device it builds fine.

It was building/archiving fine with Xcode 12 and older versions but with new Xcode 13 (and Xcode 13.1) I have problem. Where could be problem? How can I fix it?

One more thing that I get as error when archiving and not when debug build. I have this code fore get entity:

func get<Entity: NSManagedObject>
    (with predicate: NSPredicate? = nil,
     sortDescriptors: [NSSortDescriptor]? = nil,
     fetchLimit: Int? = nil,
     inContext context: NSManagedObjectContext? = nil,
     completion: @escaping (Result<[Entity], Error>) -> Void) {
    
    if let ctx = context {
        coreData.performTask({ (context) in
            do {
                let fetchRequest = Entity.fetchRequest()
                fetchRequest.predicate = predicate
                fetchRequest.sortDescriptors = sortDescriptors
                if let fetchLimit = fetchLimit {
                    fetchRequest.fetchLimit = fetchLimit
                }
                let results = try context.fetch(fetchRequest) as? [Entity]
                completion(.success(results ?? []))
            } catch {
                completion(.failure(error))
            }
        }, inContext: ctx)
    } else {
        coreData.performForegroundTask { context in
            do {
                let fetchRequest = Entity.fetchRequest()
                fetchRequest.predicate = predicate
                fetchRequest.sortDescriptors = sortDescriptors
                if let fetchLimit = fetchLimit {
                    fetchRequest.fetchLimit = fetchLimit
                }
                let results = try context.fetch(fetchRequest) as? [Entity]
                completion(.success(results ?? []))
            } catch {
                completion(.failure(error))
            }
        }
    }
}

I get these error messages:

Type 'Entity' has no member 'fetchRequest'

What's wrong? How can I fix these Core Data errors when archiving?

Thanks for help

Edit:

One more example for helper method in which I get error with no member fetchRequest:

func count(entity: NSManagedObject.Type,
           with predicate: NSPredicate? = nil,
           fetchLimit: Int? = nil,
           completion: @escaping (Result<Int, Error>) -> Void) {
    coreData.performForegroundTask { context in
        do {
            let fetchRequest = entity.fetchRequest()
            fetchRequest.predicate = predicate
            if let fetchLimit = fetchLimit {
                fetchRequest.fetchLimit = fetchLimit
            }
            let count = try context.count(for: fetchRequest)
            completion(.success(count))
        } catch {
            completion(.failure(error))
        }
    }
}
Libor Zapletal
  • 13,752
  • 20
  • 95
  • 182
  • It looks like AppEntity doesn't implement fetchRequest() from the protocol. – Joakim Danielson Oct 26 '21 at 08:13
  • Yes but why would It thinks that? It's `class AppEntity: NSManagedObject` and when just try build debug app it works. – Libor Zapletal Oct 26 '21 at 08:18
  • Off topic perhaps but why do you even need that function in your protocol? – Joakim Danielson Oct 26 '21 at 08:21
  • Good question. I made it few years ago and I have some plans with it but I guess it's not needed. I removed it and that errors are no longer. But still have errors in helper generic methods that have still problems with `no member fetchRequest`. – Libor Zapletal Oct 26 '21 at 08:29
  • Unrelated but you are using too many unnecessary optionals. For example `fetchLimit` is non-optional `Int`, a zero value is no limit. And a `fetch` returns **always** a non-optional array of `NSManagedObject` instances. If you specify the entity type in the fetch request it returns even the proper subclass entity. – vadian Oct 26 '21 at 08:56

1 Answers1

3

I got same compile errors. I can't find compile error reason, but I think this is one of the workaround:

if let entityName = Entity.entity().name {
    let request = NSFetchRequest<Entity>(entityName: entityName)
    ....
}
kumabook
  • 96
  • 1
  • 4
  • Yes, this is solution that I can archive project with and it's working and for now I am using it. But I would like to have real solution because I don't why why I have that compile error and I don't know if it could mean more problems in future. – Libor Zapletal Oct 27 '21 at 13:03
  • I totally agree with you – kumabook Oct 28 '21 at 10:12