2016-08-30 1 views
2

У меня возникают некоторые проблемы с полиморфизмом в Swift 2.2 и 2.3. Я работаю с NSManagedObjects и строит виды из определенных. Я заметил, что мой конструктор представлений не вызывал правильную перегруженную функцию, основанную на подклассе модели.Перегрузка адротических полиморфизмов/функций не работает в Swift при задании шаблона в сигнатуре функции

В Playground я возился с несколькими вещами и обнаружил следующее:

import Foundation 

class DataObject: NSObject {} 
class X: DataObject {} 
class Y: DataObject {} 

class ViewBuilder { 
    func viewForModel<S where S: DataObject>(model: S) { 
     tmp(model) 
    } 

    func tmp(model: X) { 
     print("X") 
    } 

    func tmp(model: Y) { 
     print("Y") 
    } 

    func tmp(model: DataObject) { 
     print("Base") 
    } 
} 

ViewBuilder().viewForModel(X()) 

Это печатает «Base», несмотря на прохождение типа X. Могу ли я что-то отсутствует? Почему он вызывает функцию базового класса tmp() вместо одного для соответствующего подкласса?

+0

Глобальные функции в Swift статически переданную - поэтому в методе с общий параметр, который наследуется от 'DataObject', единственная перегрузка, которая может быть вызвана, - это тот, который принимает вход DataObject. Почему бы не сделать метод 'tmp' методом экземпляра в' DataObject', позволяя подклассу переопределить его? Или определить его с помощью протокола? Один из подходов позволил бы полиморфизм. – Hamish

+0

Спасибо, @Hamish, но на самом деле мой код NSManagedObject настроен. Образец кода, демонстрирующий те же проблемы, имеет тот же результат, является ли 'tmp()' глобальным или метод класса. Я, к сожалению, не хочу помещать 'tmp()' в NSMO, поскольку это помещает слишком много информации о уровне слоя в слой модели. Притворись, что мои модели будут использовать совершенно разные виды в UITableViewCell и простой UIViewController.view. Предоставляя промежуточный объект между слоями модели и представления, который создает определенные представления для определенных моделей, я надеялся, что смогу повторно использовать модель для любого вида. –

+0

@Hamish, я обновил пример на SO, чтобы показать, что даже в качестве метода он испытывает те же проблемы, что и глобальные функции. :( –

ответ

0

Проблема заключается в том, что X прежде всего в DataObject, и вы должны бросить подкласс так:

func viewForModel<S where S: DataObject>(model: S) { 
    model.dynamicType 
    tmp(model as! X) 
} 
+0

Я не знаю, какой тип будет (за пределами этого примера отладки в моем приложении Core Data) во время компиляции, поэтому я не могу его отличить. Именно это я и надеялся на совпадение шаблонов. Все, что я знаю в 'viewForModel()', это базовый класс, и я пытаюсь понять, как заставить компилятор распознать его фактический тип и магически назвать правильный метод. –

+0

Конечно, я мог бы слишком много спрашивать компилятор. Мне просто интересно, есть ли способ сделать это или нет. –

1

Проблема подклассов здесь интригует, но мне интересно, если бы не лучше с чем-то вроде этого:

class ViewBuilder { 
    func viewForModel(model: X) { 
     print("X") 
    } 
    func viewForModel(model: Y) { 
     print("Y") 
    } 
    func viewForModel(model: DataObject) { 
     print("Base") 
    } 
} 

Это дает желаемые результаты:

ViewBuilder().viewForModel(X()) печатает "X"

ViewBuilder().viewForModel(Y()) печатает «Y»

Если у вас есть class Z: DataObject {}, который не имеет конкретного метода:

ViewBuilder().viewForModel(Z()) отпечатки «База»