Функция класса, возвращающая Self?для абстрактного класса Core Data - PullRequest
0 голосов
/ 09 октября 2018

У меня есть класс Core Data List, унаследованный от абстрактного типа Synchronizable.Последний является родительским для нескольких других классов, которые я намерен синхронизировать с моим сервером.

Я хотел бы добавить функцию класса в Synchronizable, которая возвращает объект с определенным идентификатором на сервере:

class func withIDOnServer(_ pk:String, inMOC context:NSManagedObjectContext -> Self? 

и используйте его как

List.withIDOnServer(pk:"1234", context)

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

extension Synchronizable {
// return the object with ID xxx on server. 
class func withIDOnServer(_ pk:String, inMOC context:NSManagedObjectContext) throws -> Self? {
    let entityName = String(describing: self)
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
    request.predicate = NSPredicate(format:"'pk' = %@", pk)
    do {
        let results = try context.fetch(request) as! [Self]
        guard results.count == 1 else {
            if results.count > 1 {
                throw fetchError.moreThanOne(pk: pk)
            }
            else { // results.count == 0
                return nil
            }
        }
        return results.first as! Self?
    }
    catch let error {
        throw fetchError.cannotFetch(error.localizedDescription)
    }
}

}

Проблема заключается в использовании Self в теле функции.(Я также попробовал Self? и type(of:self), не повезло) Как я могу вернуть объект того же типа, что и дочерний класс?Это единственный способ использовать протокол (где Self разрешено в теле функции)?

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

Для работы будут нужны генерики Swift.Вместо Self используйте универсальный тип Swift.Что-то вроде

extension Synchronizable {
// return the object with ID xxx on server. 
class func withIDOnServer<T:Synchronizable>(_ pk:String, inMOC context:NSManagedObjectContext) throws -> T? {
    let entityName = String(describing: self)
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
    request.predicate = NSPredicate(format:"'pk' = %@", pk)
    do {
        let results = try context.fetch(request) as! [T]
        guard results.count == 1 else {
            if results.count > 1 {
                throw fetchError.moreThanOne(pk: pk)
            }
            else { // results.count == 0
                return nil
            }
        }
        return results.first as! T?
    }
    catch let error {
        throw fetchError.cannotFetch(error.localizedDescription)
    }
}

Чтобы компилятор мог вывести правильный тип, вам нужно прояснить это при вызове функции, объявив ожидаемый тип.Что-то вроде

let myList: List? = Synchronizable.withIDOnServer("asdf", inMOC: context)
0 голосов
/ 09 октября 2018

Если подумать, объявление функции в базовом классе с типом возврата Self не имеет никакого смысла.Если подклассы не переопределяют эту функцию, вызов ее в подклассе вызовет реализацию базового класса, и он не сможет волшебным образом изменить свой тип возвращаемого значения в зависимости от того, какой класс равен self.

Предполагая, что запрос выборки Core Data возвращает List, это тип объекта, который должна возвращать эта функция.Можете ли вы быть уверены, что все результаты запроса являются экземплярами List?Если нет, приведение результата к List как минимум небезопасно.

Получив эту функцию для возврата List или Synchronizable, вы можете рассмотреть возможность добавления функции к каждому подклассу, который выполняет приведениек подклассу, например, если Foo является подклассом, он может выглядеть как (не проверено)

class Foo: Synchronizable 
{
    class functions getInstance(_ pk:String, inMOC context:NSManagedObjectContext) throws -> Foo? 
    {
        guard let ret = try withIDOnServer(pk, context: context) as? Foo
        else { throw MyError.classCast }
    }
    return ret
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...