Можете ли вы переопределить между расширениями в Swift или нет? (Компилятор кажется смущенным!)
Я работал над приложением для 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 уже видел мою проблему, но вот как я узнал об этом: недавно я попытался добавить аналогичную функциональность, используя методы, которые имеют параметры и / или возвращают значения, которые не встроены в типы, но я начал получать это ошибка: объявления в расширениях еще не могут быть переопределены.
Чтобы исследовать эту проблему, я добавил следующее в один из моих 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??
}
К моему удивлению, я получил ту же ошибку компилятора (объявления в расширениях еще не могут быть переопределены). Какие? Но я уже использовал этот шаблон несколько раз без ошибок компилятора.
Вопросы: во-первых, существуют ли определенные правила переопределения в расширениях, так что в некоторых случаях это должно работать, а в других - нет? Во-вторых (и это еще больше сбивает с толку), почему кажется, что компилятор Swift настолько несовместим? Что мне здесь не хватает? Пожалуйста, помогите мне восстановить мою веру в Свифта.
ОБНОВИТЬ:
Как отмечено в правильном ответе Мартина Р., кажется, что вы можете переопределить методы в текущей версии 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) { }
}