Можно ли использовать общие подклассы с конструкторами функций в Swift?

#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. Спасибо за ссылку на документацию! Это работает.