Я работаю над приложением iOS в Swift (большая часть его перемещается из Objective-C). Я использую Core Data и пытаюсь использовать расширения, чтобы добавить функциональность к классам, автоматически генерируемым из моей модели. Одно, что я легко сделал в Objective-C, заключалось в том, чтобы добавить метод в категорию класса A и переопределить этот метод в категории класса B (который получен из A), и я надеялся сделать то же самое в Swift.
Некоторое время теперь у меня был следующий код в моем проекте (и это всего лишь один пример), и хотя я еще не использовал эту функциональность, компилятор отлично выполнил компиляцию этого кода:
// From CellType.swift -- NOTE: Imports from Foundation and CoreData
@objc(CellType)
class CellType: NSManagedObject {
@NSManaged var maxUses: NSNumber
@NSManaged var useCount: NSNumber
// Other properties removed for brevity
}
// From SwitchCellType.swift -- NOTE: Imports from Foundation and CoreData
@objc(SwitchCellType)
class SwitchCellType: CellType {
@NSManaged var targetCellXIndex: NSNumber
@NSManaged var targetCellYIndex: NSNumber
@NSManaged var targetCellType: CellType
// Other properties removed for brevity
}
// From CellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension CellType
{
var typeLabel : String { get { return "Empty"; } }
func isEqualToType(otherCellType : CellType) -> Bool
{
return (self.typeLabel == otherCellType.typeLabel &&
self.maxUses.isEqualToNumber(otherCellType.maxUses) &&
self.useCount.isEqualToNumber(otherCellType.useCount));
}
// Code removed for brevity
}
// From SwitchCellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData
extension SwitchCellType // YES, this compiles with the overrides!
{
override var typeLabel : String { get { return "Switch"; } }
override func isEqualToType(otherCellType : CellType) -> Bool
{
var answer = false;
if let otherSwitchCellType = otherCellType as? SwitchCellType
{
answer = super.isEqualToType(otherCellType) &&
self.targetCellXIndex.isEqualToNumber(otherSwitchCellType.targetCellXIndex) &&
self.targetCellYIndex.isEqualToNumber(otherSwitchCellType.targetCellYIndex) &&
self.targetCellType.isEqualToType(otherSwitchCellType.targetCellType);
}
return answer;
}
// Code removed for brevity
}
Надеюсь, какой-то эксперт Swift уже видит мою проблему, но вот как я узнал об этом: недавно я попытался добавить аналогичную функциональность, используя методы, которые имеют параметры и/или возвращающие значения, которые не построены в типах, но я начал получать эту ошибку: объявления в расширениях еще не могут переопределить.
Чтобы изучить эту проблему, я добавил следующее в один из моих быстрых файлов, считая, что он скомпилируется просто:
class A
{
}
class B : A
{
}
extension A
{
var y : String { get { return "YinA"; } }
}
extension B
{
override var y : String { get { return "YinB"; } } // Compiler error (see below) -- What??
}
К моему удивлению, я получил ту же ошибку компилятора (объявления в расширениях еще не могут переопределить). Какие? Но я использовал этот patter несколько раз уже без ошибок компилятора.
Вопросы: Во-первых, существуют ли определенные правила об переопределении в расширениях, которые в некоторых случаях должны работать, но в других случаях это не так? Второе (и более смущающее) почему кажется, что компилятор Swift настолько непоследовательен? Что мне здесь не хватает? Пожалуйста, помогите мне восстановить мою веру в Свифт.
UPDATE:
Как указано в правильном ответе Мартина R, кажется, что вы можете переопределить методы в текущей версии Swift (1.1 через Xcode 6.1), если они (1) включают только классы, полученные из NSObject, и (2) не используйте модификатор inout. Вот несколько примеров:
class A : NSObject { }
class B : A { }
class SubNSObject : NSObject {}
class NotSubbed {}
enum SomeEnum { case c1, c2; }
extension A
{
var y : String { get { return "YinA"; } }
func f() -> A { return A(); }
func g(val: SubNSObject, test: Bool = false) { }
func h(val: NotSubbed, test: Bool = false) { }
func j(val: SomeEnum) { }
func k(val: SubNSObject, inout test: Bool) { }
}
extension B
{
// THESE OVERIDES DO COMPILE:
override var y : String { get { return "YinB"; } }
override func f() -> A { return A(); }
override func g(val: SubNSObject, test: Bool) { }
// THESE OVERIDES DO NOT COMPILE:
//override func h(val: NotSubbed, test: Bool = false) { }
//override func j(val: SomeEnum) { }
//override func k(val: SubNSObject, inout test: Bool) { }
}