Это хорошая идея, чтобы передать действие как () -> Void для компонента? - PullRequest
1 голос
/ 02 апреля 2020

Я новичок в swfitUI и создаю компонент примерно так:

// my solution
struct TodoItem {

  var title: String
  var action: (() -> Void)?

  var body: some View {
    HStack {
      Text(title)
      if let action = action {
        Button(action: action, label: Image(image))
      }
    }
  }
}

, но мои товарищи по команде не согласны с этим, они думают, что я не должен передавать действие компоненту вместо этого я должен использовать ViewBuilder, как это,

// my teammates' solution
struct TodoItem<Content>: View where Content: View {
  var title: String
  var content: Content

  @inlinable public init(title: String, @ViewBuilder content: () -> Content) {
    self.title = title
    self.content = content()
  }

  var body: some View {
    HStack {
      Text(title)
      content
    }
  }
}

, они сказали, что это более SwiftUI, но я не понимаю, с точки зрения использования, в моем решении, кто-то использует этот компонент только чтобы заботиться о названии и действии, в моих товарищах по команде, пользователь должен заботиться о названии, действии и том, как создать кнопку, очевидно, что мое решение более простое в использовании, и я не сделал вижу какие-то недостатки в моем решении.

Является ли решение моих товарищей по команде лучше моего, почему?

Ответы [ 2 ]

3 голосов
/ 02 апреля 2020

Если вы обнаруживаете, что достигли AnyView, вы оставили счастливый путь SwiftUI. Есть причина, по которой он указан в разделе редко используемых представлений в документах.

AnyView нарушает многие оптимизации SwiftUI. Он существует в качестве аварийного выхода, когда у вас нет другого выбора.

Ваш код похож на все примеры, которые я до сих пор видел в Apple. @ViewBuilder имеет смысл, когда ваша цель - создать контейнер для представления, сгенерированного вызывающей стороной, и вы хотите, чтобы вызывающая сторона определяла детали реализации. HStack - хороший пример. Если компонент должен инкапсулировать детали реализации View, то он должен генерировать само представление, используя переданные свойства (что вы и делаете). Таким образом, вопрос в этом случае таков: «Является ли TodoItem общим инструментом, который будет использоваться разными способами многими разными пользователями?» Если нет, я не уверен, почему вы передадите ViewBuilder.


Ваше обновление (удаление AnyView) несколько меняет вопрос. В этом случае все сводится к моему последнему абзацу, приведенному выше: если TodoItem предназначен для создания универсального c контейнера, для которого ожидающие должны предоставлять содержимое, то ViewBuilder хорош. Предполагается, что TodoItem имеет отношение к макету, а не к отображению, как HStack.

Но если это представление о отображении, например Button или Text, то вы должны передать его свойства и позволить ему управлять своими внутренними объектами. (Обратите внимание, что кнопка позволяет передавать вам в Label ViewBuilder, но обычно это не требуется.)

Имя, подобное "TodoItem", очень похоже на последнее; это похоже на пользовательский вид, который должен управлять своим внешним видом. Но главный вопрос: сколько абонентов передают разные Views этому ViewBuilder? Если все вызывающие абоненты передают почти одинаковые представления (или если есть только один вызывающий), то это должны быть свойства (например, кнопка). Если есть много абонентов, которые передают различные виды представлений содержимого, то он должен использовать ViewBuilder (например, HStack).

Ни один из них не является «более SwiftUI». Они решают различные проблемы в SwiftUI.

1 голос
/ 02 апреля 2020

Ваш подход правильный, только изменения (let не сработает), поэтому см. Ниже исправлено:

struct TodoItem {

  var title: String
  var image: String          // << this might also needed
  var action: (() -> Void)?

  var body: some View {
    HStack {
      Text(title)
      if action != nil {      // << here !!
        Button(action: action!, label: { Image(image) })
      }
    }
  }
}

Протестировано с Xcode 11.4 / iOS 13.4

О программе заместитель товарища по команде : сохранение View в элементе не является "модой SwiftUI" ... поэтому, исправляя второй вариант, я сохраню ViewBuilder в элементе и использую его для внедрения View внутри body. Но в любом случае это худший подход, потому что нарушает целостность компонента пользовательского интерфейса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...