Общий FetchRequest

У меня есть статическая функция, которая расширяет NSManagedObject, чтобы получить такой объект...

NSManagedObject.get(type: MYUser.self, with: ("id", "SomeUserId"), in: context)

extension NSManagedObject {

    static func get<M: NSManagedObject>(type: M.Type, with kvp: (String, CVarArg), in context: NSManagedObjectContext) -> M? {

     guard let name = entity().name else { return nil }
     guard M.entity().propertiesByName[kvp.0] != nil else { Assert("\(name) does not have \(kvp.0)"); return nil }

     let fetchRequest = NSFetchRequest<M>(entityName: name)
     fetchRequest.predicate = NSPredicate(format: "\(kvp.0) == %@", kvp.1)

     do {
            let object = try context.fetch(fetchRequest)
            if let foundObject = object.first { return foundObject }
            return nil
        } catch {
            return nil
        }
    }
}    

Синтаксис, который я хотел бы,

MYUser.get(with: ("id", "SomeUserId"), in: context)

и вывести тип из класса, который сделал вызов... но я не уверен, что здесь поставить вместо общего

NSFetchRequest<M>(entityName: name)

NSFetchRequest<???>(entityName: name)

заранее спасибо


person Magoo    schedule 27.09.2018    source источник
comment
Установка M в качестве универсального типа не работает для вас?   -  person Sweeper    schedule 27.09.2018
comment
Я хочу удалить общий тип   -  person Magoo    schedule 27.09.2018
comment
Это будет ноль, верно?   -  person Magoo    schedule 27.09.2018
comment
О, извините, я неправильно понял ваш вопрос. Сейчас думаю над ответом...   -  person Sweeper    schedule 27.09.2018
comment
Я полагаю, вы не хотите делать что-то вроде let user: MYUser? = MYUser.get(...)?   -  person Sweeper    schedule 27.09.2018
comment
Я мог бы захотеть сделать это, да   -  person Magoo    schedule 27.09.2018
comment
Это в основном о более чистом синтаксисе   -  person Magoo    schedule 27.09.2018
comment
Это должно быть то, что вы ищете: «передача универсального класса в качестве аргумента функции в swift»> stackoverflow.com/questions/51174234/.   -  person Martin R    schedule 27.09.2018
comment
Ах да, вот оно!   -  person Magoo    schedule 27.09.2018


Ответы (2)


Если вы не против написать MYUser дважды, вы можете удалить параметр type и указать тип, чтобы Swift мог вывести M:

extension NSManagedObject {

    static func get<M: NSManagedObject>(with kvp: (String, CVarArg), in context: NSManagedObjectContext) -> M? {

        guard let name = entity().name else { return nil }
        guard M.entity().propertiesByName[kvp.0] != nil else {
            print("\(name) does not have \(kvp.0)")
            return nil
        }

        let fetchRequest = NSFetchRequest<M>(entityName: name)
        fetchRequest.predicate = NSPredicate(format: "\(kvp.0) == %@", kvp.1)

        do {
            let object = try context.fetch(fetchRequest)
            if let foundObject = object.first { return foundObject }
            return nil
        } catch {
            return nil
        }
    }
}

// usage:
let user: MYUser? = MYUser.get(with: ("id", "SomeUserId"), in: context)

Если вы не хотите писать MYUser дважды, то я не могу придумать никаких решений. Если бы NSManagedObject был протоколом, вы могли бы использовать там Self.

person Sweeper    schedule 27.09.2018
comment
Просто для ясности let user = MYUser.get(with: ("id", "SomeUserId"), in: context) не сработает? - person Magoo; 27.09.2018
comment
Тип @Magoo user либо не может быть определен, либо просто NSManagedObject. Попробуй сам. - person Sweeper; 27.09.2018
comment
@Magoo, на самом деле, решение, показанное в ссылке Мартина Р., тоже довольно хорошее. Попробуйте его адаптировать. - person Sweeper; 27.09.2018

На основе ссылки Передача универсального класса в качестве аргумента функция в swift, предложенная Martin R

protocol Managed where Self: NSManagedObject { }

extension Managed where Self: NSManagedObject {

static func get(with kvp: (String, CVarArg), in context: NSManagedObjectContext) -> Self? {

    guard let name = entity().name else { return nil }
    guard entity().propertiesByName[kvp.0] != nil else { Assert("\(name) does not have \(kvp.0)"); return nil }

    let fetchRequest = NSFetchRequest<Self>(entityName: name)
    fetchRequest.predicate = NSPredicate(format: "\(kvp.0) == %@", kvp.1)

    do {
        let object = try context.fetch(fetchRequest)
        if let foundObject = object.first { return foundObject }
        return nil
    } catch {
        return nil
    }
}
person Magoo    schedule 27.09.2018
comment
Ответы будут более полезными, если вы объясните проблему и решение, а не только код. – Вы также можете добавить ссылку на заголовок stackoverflow.com/questions/51174234/ на ваш ответ, поскольку вы, очевидно, были вдохновлены этим решением. - person Martin R; 27.09.2018
comment
Конечно... Я думал, что это ясно из комментариев, но вы правы, я должен процитировать вас и ответ, на который вы мне указали. - person Magoo; 28.09.2018