#swift
Вопрос:
В Swift я хочу, чтобы мой статический метод базового класса возвращал объекты подкласса, когда статический метод вызывается из подкласса.
При возврате одного объекта подкласса я могу сделать это возможным с помощью init(). Но при возврате нескольких объектов подкласса init() нельзя использовать.
И я хочу не только просто возвращать объекты подкласса из родительского статического метода, но и реализовать некоторую логику, отличную от создания экземпляра в родительском статическом методе, и заставить статический метод каждого подкласса наследовать поведение родительского статического метода.
У меня есть 3 подкласса. Итак, я не хочу писать один и тот же код в статических методах 3 подклассов. Как я должен поступить?
Если возможно, я также хочу использовать статический метод вместо init() для возврата одного объекта подкласса.
class Base {
func f() {
print("base class")
}
// this does not works. it creates a base class object.
static func createSubclassObject() -> Base {
return Base()
}
// this works. it creates a subclass object.
init() {
}
// this does not work. base class objects are created.
static func createSubclassObjects(count: Int) -> [Base] {
var objects = [Base]()
for _ in 0 ..< count {
objects.append(Base())
}
return objects
}
/* probably I need something like this. but this code generates a compile error
static func createSubclassObjects(count: Int) -> [Self] {
var objects = [Self]()
for _ in 0 ..< count {
objects.append(Self())
}
return objects
}
*/
// generic also does not work. this returns a base class object.
static func createSubclassObjectByGeneric<T: Base>() -> T {
return T()
}
}
class Sub: Base {
override func f() {
print("sub class")
}
}
print(Sub().f())
// sub class・
print(Sub.createSubclassObject().f())
// base class
Sub.createSubclassObjects(count: 2).forEach {
print($0.f())
}
// base class
// base class
print(Sub.createSubclassObjectByGeneric().f())
// base class
Ответ №1:
Тебе нужно вернуться Self
, а не Base
.
static func createSubclassObject() -> Self {
.init()
}
required init() { }
Кроме того, не используйте цикл for. Существует инициализатор массива, предназначенный для того, что вы делаете.
static func createSubclassObjects(count: Int) -> [Base] {
.init(repeating: createSubclassObject(), count: count)
}
Комментарии:
1. спасибо вам за отличный ответ! Это прекрасно работает. Ваш ответ-это то, что я так долго искал. И я обнаружил
Array(repeating: Self.init(), count: count)
, что также возвращает объекты подкласса. НоArray(repeating: .init(), count: count)
возвращает объекты базового класса.
Ответ №2:
Работает следующий код. Но я думаю, что должны быть лучшие решения, потому что я не хочу определять class func sub()
в родительском классе и переопределять class func sub()
в каждом подклассе.
ПРАВКА: Смотрите ответ Джесси, который является лучшим решением.
class Base {
func f() {
print("base class")
}
static func createSubclassObjects(count: Int) -> [Base] {
var objects = [Base]()
for _ in 0 ..< count {
//objects.append(Base())
objects.append(Self.sub())
}
return objects
}
class func sub() -> Base {
Base()
// or use fatalError() if you don't need to call createSubclassObjects(count: Int) from the base class
}
}
class Sub1: Base {
override func f() {
print("sub1 class")
}
override class func sub() -> Base {
Sub1()
}
}
class Sub2: Base {
override func f() {
print("sub2 class")
}
override class func sub() -> Base {
Sub2()
}
}
Base.createSubclassObjects(count: 2).forEach {
print($0.f())
}
// base class
// base class
Sub1.createSubclassObjects(count: 2).forEach {
print($0.f())
}
// sub1 class
// sub1 class
Sub2.createSubclassObjects(count: 2).forEach {
print($0.f())
}
// sub2 class
// sub2 class