Что означает «идентичность» в SwifUI и как мы можем изменить «идентичность» чего-либо - PullRequest
3 голосов
/ 13 апреля 2020

Я новичок в SwiftUI, и у меня проблемы с представлением оповещений вплотную.

Описание модификатора .alert(item:content:) записано в его определении:

/// Presents an alert.
    ///
    /// - Parameters:
    ///     - item: A `Binding` to an optional source of truth for the `Alert`.
    ///     When representing a non-nil item, the system uses `content` to
    ///     create an alert representation of the item.
    ///
    ///     If the identity changes, the system will dismiss a
    ///     currently-presented alert and replace it by a new alert.
    ///
    ///     - content: A closure returning the `Alert` to present.

    public func alert<Item>(item: Binding<Item?>, content: (Item) -> Alert) -> some View where Item : Identifiable

Меня особенно интересует часть If the identity changes, the system will dismiss a currently-presented alert and replace it by a new alert. Поскольку я хочу, чтобы оповещения были представлены вплотную, если я каким-то образом смогу изменить «идентичность», я смогу достичь желаемой функциональности, то есть заставить систему отклонить текущее оповещение. и заменив старый Alert новым Alert (back-to-back).

Если кто-то может объяснить мне, что такое «идентичность» и как я могу изменить «идентичность» чего-то, я буду чрезвычайно признательна.

(Или, если вы знаете лучший способ представления предупреждений, который также будет очень полезен.)

Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 13 апреля 2020

Обратите внимание, что для этого метода требуется Binding<Item?>, а Item должно быть Identifiable. Для параметра Binding<Item?> вы должны передать «источник правды», который управляет тем, как выглядит отображаемое предупреждение, или показывает ли предупреждение вообще. Когда этот источник правды изменяется (то есть становится чем-то другим), представление обновит предупреждение.

Но вот проблема, как SwiftUI узнает, что означает «изменение» в контексте вашей модели? Допустим, Item - это класс Person, который вы написали. Person имеет name и age. Ваша работа - сказать SwiftUI, что «Person становится совершенно другим человеком, когда его имя меняется». (Конечно, у вас могло бы быть какое-то другое определение того, что здесь подразумевается под «изменением человека». Это определение является лишь примером.)

struct Person : Identifiable {
    var id: String {
        name
    }

    let name: String
    let age: Int
}

Именно поэтому Item должно быть Identifiable , Item.id является, таким образом, «идентичностью».

Обратите внимание, что Identifiable отличается от Equatable тем, что Identifiable задает вопрос "что делает этого человека другим человеком?" тогда как Equatable спрашивает «какой результат вы бы хотели == дать?». См. this для другого примера.

как мы можем изменить «идентичность» чего-либо?

Просто измените привязку, которую вы передаете (например, установить @State, на котором основана привязка) таким образом, что его id изменится.

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

Ниже приведена демонстрация использования предупреждений. И некоторые результаты расследования об изменении личности, как документально подтверждено.

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

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

struct SomeItem: Identifiable { // identifiable item
    var id: Int // identity
}

struct DemoAlertOnItem: View {

    @State private var selectedItem: SomeItem? = nil

    var body: some View {
        VStack {
            ScrollView (.vertical, showsIndicators: false) {
                ForEach (0..<5) { i in

                    Text("Item \(i)").padding()
                    .onTapGesture {
                        self.selectedItem = SomeItem(id: i)

                        // below simulate change identity while alert is shown
                        DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                            self.selectedItem = nil                    // works !!

                            // self.selectedItem?.id = 100             // crash !!
                            // self.selectedItem = SomeItem(id: 100)  // crash !!
                        }
                    }
                }
            }
        }
        .alert(item: self.$selectedItem) { item in
             Alert(title: Text("Alert"), message: Text("For item \(item.id)"), dismissButton: .default(Text("OK")))
        }
    }
}
...