SwiftUI и объединить

Я слежу за видео на YouTube-канале Firebase. Начиная примерно с 27:45, инструктор пытается установить переменную на основе логического значения и в итоге получает следующий код в init(task: Task):

$task
    .map { task in
        task.isCompleted ? "checkmark.circle.fill" : "circle"
    }
    .assign(to: \.completionStateIconName, on: self)
    .store(in: &cancellables)

Мне это кажется слишком запутанным. Во-первых, я не могу найти документацию по использованию .map для объекта структуры, только для массивов и т. д. Во-вторых, что с этим &cancellables? (Он определяется как private var cancellables = Set<AnyCancellable>() до init{}.) В-третьих, почему весь этот код, а не просто:

task.completionStateIconName = task.isCompleted ? "checkmark.circle.fill" : "circle"

Кажется, что это дает тот же результат, но будет ли что-то в дальнейшем, что первый фрагмент кода работает, а второй - нет?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
49
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

$task (с префиксом $) является прогнозируемым значением оболочки свойства @Published и возвращает переменную типа Published.Publisher. Другими словами, это издатель Combine, который публикует значение всякий раз, когда свойство - в данном случае Task - изменяется.

Если вы не узнали о фреймворке Combine (или других реактивных фреймворках), этого ответа определенно будет недостаточно. На высоком уровне издатель Combine генерирует значения, которые вы можете преобразовать с помощью операторов, таких как .map, и в конечном итоге подписаться на них, например, с помощью .sink или .assign.

Итак, построчно:

// a publisher of Task values
$task 
  // next, transform Task into a String using its isCompleted property
  .map { task in
     task.isCompleted ? "circle.fill" : "circle"
  }
  // subscribe, by assigning the String value to the completionStateIconName prop
  .assign(to: \.completionStateIconName, on: self)

Теперь приведенное выше возвращает экземпляр AnyCancellable, который вам нужно сохранить, пока вы хотите получать значения. Таким образом, вам нужно либо сохранить его непосредственно как свойство, либо использовать .store, чтобы добавить его в Set<AnyCancellable> - распространенный подход.


Итак, почему это так запутано? Предположительно, это построено так, что если свойство task когда-либо изменится, конвейер Combine обновит свойство completionStateIconName.

Если вы только что сделали:

completionStateIconName = task.isCompleted ? "circle.fill" : "circle"

это присвоило бы значение только в начале.


При этом в данном конкретном случае использование Combine может быть излишне запутанным, в то время как использование просто didSet:

var task: Task {
   didSet {
      completionStateIconName ? task.isCompleted ? "circle.fill" : "circle"
   }
}

Учитывая, что Task - это struct, didSet подойдет. Но то же самое и с вычисляемым свойством var completionStateIconName: String { completionStateIconName ? task.isCompleted ? "circle.fill" : "circle" }. И просматривая оставшуюся часть видео, мы видим, что он даже не конвертирует TaskCell для использования completionStateIconName, так что нет никаких причин вводить это свойство вообще!

rob mayoff 02.04.2021 09:58

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

New Dev 02.04.2021 13:03

@NewDev @rob Спасибо. Я забыл предложить однострочник как часть didSet или вычисляемого значения, но на самом деле я думал именно об этом. Спасибо, что нашли время, чтобы ответить так подробно. Я знаю из Combine, но точно не знать. @rob Я думаю, у вас есть лишний кусок в вашем троичном выражении, не так ли? Вы не имеете в виду только var completionStateIconName: String { task.isCompleted ? "circle.fill" : "circle" }?

Zonker.in.Geneva 02.04.2021 14:02

Я продолжу это видео и последующие видео и посмотрю, станет ли использование Combine необходимым в будущем ...

Zonker.in.Geneva 02.04.2021 14:04

Другие вопросы по теме