'identity' 在 SwiftUI 中是什么意思以及我们如何更改某些内容的 'identity'

What does 'identity' mean in SwifUI and how do we change the 'identity' of something

我是 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 部分特别感兴趣。由于我希望连续显示警报,如果我能够以某种方式更改 'identity',我将能够实现我想要的功能 - 让系统关闭当前 -显示警报并用新警报替换旧警报(背靠背)。

如果有人能向我解释 'identity' 是什么以及我如何更改某些内容的 'identity',我将不胜感激。

(或者,如果您知道一种更好的连续显示警报的方法,那也会非常有帮助。)

提前致谢!

请注意此方法如何需要 Binding<Item?>,而 Item 应该是 Identifiable。对于 Binding<Item?> 参数,您应该传入一个 "source of truth" 来控制显示的警报的外观,或者是否显示警报。当这个真相来源发生变化时(即变成其他东西),视图将更新警报。

但这就是问题所在,SwiftUI 如何知道 "change" 在模型上下文中的含义?假设 Item 是您编写的 Person class。 Person 有一个 nameage。告诉 SwiftUI 是你的工作,"a Person becomes a totally different person when its name changes"。 (当然,您可以在这里对 "a person changes" 的含义有一些其他定义。这个定义只是一个例子。)

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

    let name: String
    let age: Int
}

这就是为什么 Item 必须是 IdentifiableItem.id 因此是 "identity"。

请注意 IdentifiableEquatable 不同,因为 Identifiable 提出问题 "what makes this person a different person?" 而 Equatable 提出 "what result would you want == to give?"。另一个例子见 this

how do we change the 'identity' of something?

只需更改您传入的绑定(例如,设置绑定所基于的 @State),使其 id 发生变化。

在下面找到按项目使用警报的演示。以及一些关于改变身份的调查结果记录在案。

正如您发现通过用户交互激活的示例(通过点击行)进行试验一样,警报工作正常,但以编程方式更改身份,如文档所述,似乎还不稳定,但警报确实已更新。

测试 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")))
        }
    }
}