#ios #swift #function-builder
#iOS #swift #конструктор функций
Вопрос:
При использовании конструкторов функций я не могу использовать закрытие построителя переменных возврата для объекта в сочетании с подклассами generics. Игровую площадку Swift можно найти здесь .
Во-первых, давайте определим наш конструктор функций. В этом случае я буду использовать тот, который поддерживает как инициализацию массива переменных, так и общие:
@_functionBuilder struct Builder<T> {
static func buildBlock(_ items: T...) -> [T] {
items
}
static func buildBlock(_ items: [T]) -> [T] {
items
}
}
Затем я определил общий объект контейнера, который поддерживает инициализацию конструктора и сохраняет массив объектов.
class Container<T> {
let items: [T]
init(@Builder<T> builder: () -> [T]) {
self.items = builder()
}
}
Наконец, я подклассировал этот объект, чтобы определить абстракцию «Навигационного контроллера»:
struct View { }
final class NavigationController: Container<View> { }
let nav = NavigationController {
View()
}
Именно здесь Xcode выдает следующую ошибку: Cannot convert value of type 'View' to closure result type '[View]'
.
Это кажется странным, потому что конструктор функций должен знать, как использовать инициализатор переменных вместо инициализатора массива, но нет.
Чтобы проверить мою теорию, я определил объект, который не подкласс другого, но использовал синтаксис builder, как он определен в моей общей Container
реализации.
class Nav {
let views: [View]
init(@Builder<View> builder: () -> [View]) {
views = builder()
}
}
let y = Nav {
View()
}
Эта работа работает нормально, компилируется и запускается без проблем. Казалось бы, подклассы в сочетании с универсальными вводят компилятор в заблуждение относительно того, какое определение инициализации конструктора функций использовать, то, которое возвращает массив или тот, который возвращает список переменных.
Кто-нибудь сталкивался с этим раньше?
Ответ №1:
Эта проблема не связана с дженериками. Здесь происходит то, что автоматическое наследование инициализатора не «наследует» атрибут @Builder<T>
, поэтому, по сути, NavigationController
инициализатор имеет следующий вид:
init(builder: () -> [View]) {...}
Вы можете переопределить init
:
final class NavigationController: Container<View> {
override init(@Builder<View> builder: () -> [View]) {
super.init(builder: builder)
}
}
Комментарии:
1. Спасибо за ссылку на документацию! Это работает.