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

五迷三道 提交于 2020-12-09 09:47:18

问题


I'm new to SwiftUI and I'm having problems with presenting Alerts back-to-back.

The description of the .alert(item:content:) modifier has this written in it's definition:

/// 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

I'm particularly interested in the If the identity changes, the system will dismiss a currently-presented alert and replace it by a new alert part. Since I want Alerts to be presented back-to-back, if I'm somehow able to change the 'identity', I'll be able to achieve the functionality that I want - which is having the system dismiss the currently-presented alert and replacing the old Alert with a new Alert (back-to-back).

If someone can explain to me what 'identity' is and how I can change the 'identity' of something I'll be extremely grateful.

(Or if you know a better way to present alerts back-to-back that'll also be very very helpful.)

Thanks in advance!


回答1:


Find below demo of alert-by-item usage. And some investigation results about changing identity as documented.

As you find experimenting with example (by tap on row) alert activated by user interaction works fine, but changing identity programmatically, as documented, seems not stable yet, however alert is really updated.

Tested with 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")))
        }
    }
}



回答2:


Notice how this method requires a Binding<Item?>, and that Item should be Identifiable. For the Binding<Item?> parameter, you're supposed to pass in a "source of truth" that controls what the alert shown looks like, or whether the alert shows at all. When this source of truth changes (i.e. becomes something else), the view will update the alert.

But here's the problem, how does SwiftUI know what does "change" mean in the context of your model? Let's say Item is a Person class that you wrote. Person has a name and age. It is your job to tell SwiftUI, that "a Person becomes a totally different person when its name changes". (Of course, you could have some other definition of what is meant by "a person changes" here. This definition is just an example.)

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

    let name: String
    let age: Int
}

This is why Item must be Identifiable. Item.id is thus the "identity".

Note that Identifiable is different from Equatable, in that Identifiable asks the question "what makes this person a different person?" whereas Equatable asks "what result would you want == to give?". See this for another example.

how do we change the 'identity' of something?

Just change the binding you pass in (e.g. setting the @State that the binding is based on) in such a way that its id changes.



来源:https://stackoverflow.com/questions/61183557/what-does-identity-mean-in-swifui-and-how-do-we-change-the-identity-of-somet

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!