UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Explanation/Advice to Self (not self) needed

Forums > Swift

In my app I have an extension to NSManagedObject which is:

extension NSManagedObject {

    static func getObjectFor(_ uuid: UUID, in context: NSManagedObjectContext) -> Self? {
        let fetchRequest: NSFetchRequest<Self> = NSFetchRequest<Self>(entityName: Self.description())
        fetchRequest.predicate = NSPredicate(format: "id == '\(uuid)'")
        let results = try! context.fetch(fetchRequest)
        if results.count == 1 {
            return results[0]
        }
        return nil
    }

    static func getAllObjectFor(_ context: NSManagedObjectContext) -> [NSManagedObject] {
        let fetchRequest: NSFetchRequest<Self> = NSFetchRequest<Self>(entityName: Self.description())
        let results = try! context.fetch(fetchRequest)
        if results.count > 1 {
            return results
        }
        return [Self]()
    }
}

For the second function I would like to use [Self] as return type but I can't because of "Covariant 'Self' can only appear at the top level of method result type". Is there a way that I can use Self in some way to avoid casting my array of NSManagedObjects to the concrete types?

2      

Here's the version I use.

public protocol DDRCoreData where Self: NSManagedObject {

    /// fetch NSManagedObject items for a specific entity type; default implementation provided below in extension
    ///
    /// in order to use this, with the default implementation, use Xcode's codegen option of Category/Extension
    /// and then write class such as:
    ///
    /// @objc(Person) final class Person: NSManagedObject, DDRCoreData { }
    ///
    /// the class must be declared final so that [Self] can be used as the return type
    ///
    /// - Parameters:
    ///   - context: the NSManagedObjectContext to fetch the values in
    ///   - predicate: optional NSPredicate to limit the values that are fetched
    ///   - sorters: optional array of NSSortDescriptors to sort them by
    /// - Returns: an array of the matching items sorted by the sort descriptors
    static func items(for context: NSManagedObjectContext, sortedBy sorters: [NSSortDescriptor]?, matching predicate: NSPredicate?) throws -> [Self]
}

public extension DDRCoreData {

    static func items(for context: NSManagedObjectContext, sortedBy sorters: [NSSortDescriptor]? = nil, matching predicate: NSPredicate? = nil) throws -> [Self] {
        let request: NSFetchRequest<Self> = NSFetchRequest(entityName: String(describing: Self.self))
        request.predicate = predicate
        request.sortDescriptors = sorters
        do {
            let results = try context.fetch(request)
            return results
        } catch {
            print("error fetching", String(describing: Self.self), error.localizedDescription)
            return []
        }
    }
}

Then I have Xcode generate category/extension versions of the NSManaged Object and declare the class as:

@objc(Person) final public class Person: NSManagedObject, DDRCoreData { }

Then I can use:

do {
let p = try Person.items(for: managedObjectContext, sortedBy: [], matching: nil)
} catch {

}

HTH, Dave

2      

Instead of doing these functions in an extension on NSManagedObject, do them as generic functions in an extension on NSManagedObjectContext:

extension NSManagedObjectContext {
    func getObject<T:NSManagedObject>(for uuid: UUID) -> T? {
        let fetchRequest: NSFetchRequest<T> = NSFetchRequest<T>(entityName: T.description())
        fetchRequest.predicate = NSPredicate(format: "id == '\(uuid)'")
        if let results = (try? fetch(fetchRequest)), results.count == 1 {
            return results[0]
        }
        return nil
    }

    func getAllObjects<T:NSManagedObject>() -> [T] {
        let fetchRequest: NSFetchRequest<T> = NSFetchRequest<T>(entityName: T.description())
        let results = (try? fetch(fetchRequest)) ?? [T]()
        return results
    }

}

Then you can do something like this:

//assuming Item is one of your NSManagedObject subclasses
let item: Item? = context.getObject(for: id)
let allItems: [Item] = context.getAllObjects()

3      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.