Скажем, у меня есть пользовательский подкласс UIView с назначенным инициализатором:
class MyView: UIView {
init(custom: String) {
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Как и ожидалось, я не могу вызывать MyView(frame:.zero)
поскольку он не унаследован автоматически от UIView
.
Тогда предположим, что у меня есть класс построителя вида:
class Builder<V: UIView> {
func build() -> V? {
// Check if can call init(frame:) or not
if V.instancesRespond(to: #selector(V.init(frame:))) {
return V.init(frame: .zero) // <-- Crash here, because the check doesn't work
} else {
return nil
}
}
}
Здесь я проверил сначала, если пользовательский вид V
имеет init(frame:)
или нет, если да, то вызовите его.
Однако это не сработает, Builder<MyView>().build()
сбой:
Неустранимая ошибка: использование нереализованного инициализатора 'init (frame :)' для класса '__lldb_expr_14.MyView'
V.instancesRespond(to: #selector(V.init(frame:)))
всегда возвращает true
, делая эту проверку бесполезной. (Или я использовал его неправильно?)
Вопрос: Как проверить, действительно ли общий класс V
класса отвечает на init(frame:)
?
Обновлено 1: я также попробовал V.responds(to: #selector(V.init(frame:)))
как отмечали @kamaldeep и @Pranav. Тем не менее, он всегда возвращает false
независимо от того, я переопределяю init (frame :) в MyView
или нет.
Обновлено 2: Что я пытаюсь сделать:
Чтобы быть более ясным, я создаю фреймворк, который автоматически инициализирует UIView
из этого перечисления:
enum ViewBuildMethod {
case nib
case nibName(String)
case frame(CGRect)
case custom(() -> UIView)
}
и это представление, которое будет использоваться с каркасом, должно принять этот протокол и указать, как его построить:
protocol SomeViewProtocol where Self: UIView {
// ... other funcs
static func buildMethod() -> ViewBuildMethod
}
Проблема в том, что я хочу override init(frame:)
как необязательный и MyView
настраиваемый инициализатор (например, в MyView
). Затем испустите fatalError
с сообщением об ошибке, когда init(frame:)
используется (косвенно) в представлении, которое еще не переопределило его. Это указывает на незаконное использование структуры (например, MyView
buildMethod
возвращает .frame(.zero)
), который не может быть проверен во время компиляции:
class MyView: UIView, SomeViewProtocol {
init(custom: String) {
super.init(frame: .zero)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// ILLEGAL!!
static func buildMethod() -> ViewBulidMethod {
return .frame(.zero) // <-- Illegal, the framework will call V.init(frame: .zero) eventually
}
// LEGAL
// static func buildMethod() -> ViewBuildMethod {
// return .custom({ () -> UIView in
// return MyView(custom: "hello")
// })
// }
}
Сообщение об ошибке может быть похоже на V.init(frame:) is called indirectly but V doesn't override this designated initializer. Please override init(frame:) to fix this issue
V.init(frame:) is called indirectly but V doesn't override this designated initializer. Please override init(frame:) to fix this issue
. Я могу разрешить ему сбой, как описано выше, но будет яснее, если я смогу добавить какое-то содержательное сообщение, прежде чем это произойдет.