为什么这个SwiftUI警报显示得如此急切?

rjzwgtxy  于 2022-12-10  发布在  Swift
关注(0)|答案(1)|浏览(141)

警报在不应该显示时显示

我正在将Apple的HIG整合到我的应用程序中。因此,我希望在重要数据即将被删除时向用户显示警报。

MRE -你的帕尔斯

在这个示例应用中,用户管理自己的好友关系。在清理社交圈时,用户可能会不小心删除一个很酷的Dude。当这种情况发生时,即 * 当至少有一个DudeisCool == true * 时,应用将显示一个警报。如果不是这样,它应该删除所有selectedDudesIDs中表示的帅哥。

问题

目前,该应用实现了它的主要目标-不允许在未经确认的情况下删除cool Dude。然而,由于某种原因,当用户选择了非cool Dude时,会向用户显示一个空的警告。

MRE代码

这是一个Swift Playground的代码,说明了这个问题,“电池包括在内”。

import SwiftUI
import PlaygroundSupport

struct TestView: View {
    @State private var selectedDudesIDs = Set<Dude.ID>()
    @State private var editMode: EditMode = .inactive
    @State private var dudes: [Dude] = [Dude(name: "John", isCool: false), Dude(name: "Paul", isCool: true)]
    // MARK: deleting alert
    /// A boolean flag initiating deletion.
    ///
    /// Its property observer determines whether there are any cool dudes, i.d. `dude.isCool == true` among the ones to be deleted.
    @State private var isDeletingDudes: Bool = false {
        willSet {
            let coolDudesAmongDeleted = dudes.filter { dude in
                selectedDudesIDs.contains(dude.id)
            }.filter { dude in
                dude.isCool
            }
            if !coolDudesAmongDeleted.isEmpty {
                coolDudesToBeDeletedCount = coolDudesAmongDeleted.count
            }
        }
    }
    @State private var coolDudesToBeDeletedCount: Int?
    
    /// Removes dudes with selected IDs from your `dudes`.
    func endFriendship() {
        dudes = dudes.filter { dude in
            !selectedDudesIDs.contains(dude.id)
        }
    }
    
    var body: some View {
        VStack {
            HStack {
                EditButton()
                Spacer()
            }
            Text("Your pals")
                .font(.title)
            List(dudes, selection: $selectedDudesIDs) { dude in
                Text(dude.name)
            }
            if editMode.isEditing && !selectedDudesIDs.isEmpty {
                Button(role: .destructive) {
                    isDeletingDudes = true
                } label: {
                    Text("They ain't my pals no more")
                }
            }
        }
        .environment(\.editMode, $editMode)
        // gimme some proportions
        .padding()
        .frame(minWidth: 500*0.9, minHeight: 500*1.6)
        .alert("End Friendship", isPresented: $isDeletingDudes, presenting: coolDudesToBeDeletedCount) { count in
            Button(role: .destructive) {
                endFriendship()
                coolDudesToBeDeletedCount = nil
            } label: {
                Text("End Friendships")
            }
            Button(role: .cancel) {
                coolDudesToBeDeletedCount = nil
            } label: {
                Text("Cancel")
            }
        } message: { _ in
            Text("You're are about to end friendship with at least one cool dude.")
        }
    }
}

struct Dude: Identifiable {
    var id: String { self.name }
    let name: String
    var isCool: Bool
}

let view = TestView()
PlaygroundPage.current.setLiveView(view)

MRE在行动

一个27秒长的剪辑,说明当前行为。

在这里,用户知道两个Dude-John只是一个朋友,Paul是一个很酷的朋友。当删除John时,警告应该显示。
为什么我认为这不是我的错
documentation of alert属性 Package 函数会读取:For the alert to appear, both isPresented must be true and data must not be nil.在本例中,尽管数据*(在本例中为coolDudesToBeDeletedCount)*nil,但仍显示警报。我已使用属性观察器对此变量进行了检查,在实际选择一个很酷的Dude之前,它为零。
此外,data参数的类型为T?,这是一个泛型Optional-并且Int?绝对适合该角色。

总结

我的程序设计有问题还是文档有问题?无论哪种情况,我如何才能达到我想要的结果?如何只在必要时显示警告?

gcuhipw9

gcuhipw91#

是的,看起来文档是误导性的。只有isPresented控制警报的可见性,presenting将调用闭包。如果presentingnil,则闭包代码将不会执行。

**解决方法:**建立var showAlert以控制警示的可见性。

import SwiftUI

struct Dude: Identifiable {
    var id: String { self.name }
    let name: String
    var isCool: Bool
}

struct ContentView: View {
    @State private var selectedDudesIDs = Set<Dude.ID>()
    @State private var editMode: EditMode = .inactive
    @State private var dudes: [Dude] = [Dude(name: "John", isCool: false), Dude(name: "Paul", isCool: true)]
    // MARK: deleting alert
    /// A boolean flag initiating deletion.
    ///
    /// Its property observer determines whether there are any cool dudes, i.d. `dude.isCool == true` among the ones to be deleted.
    @State private var isDeletingDudes: Bool = false {
        willSet {
            let coolDudesAmongDeleted = dudes.filter { dude in
                selectedDudesIDs.contains(dude.id)
            }.filter { dude in
                dude.isCool
            }
            print(coolDudesAmongDeleted)
            if !coolDudesAmongDeleted.isEmpty {
                coolDudesToBeDeletedCount = coolDudesAmongDeleted.count
                showAlert = true
            }else{
                showAlert = false
                endFriendship()
            }
        }
    }
    @State private var showAlert: Bool = false
    @State private var coolDudesToBeDeletedCount: Int?
    
    /// Removes dudes with selected IDs from your `dudes`.
    func endFriendship() {
        dudes = dudes.filter { dude in
            !selectedDudesIDs.contains(dude.id)
        }
    }
    
    var body: some View {
        VStack {
            HStack {
                EditButton()
                    .padding(.leading, 24)
                Spacer()
            }
            Text("Your pals")
                .font(.title)
            List(dudes, selection: $selectedDudesIDs) { dude in
                Text(dude.name)
            }
            if editMode.isEditing && !selectedDudesIDs.isEmpty {
                Button(role: .destructive) {
                    isDeletingDudes = true
                } label: {
                    Text("They ain't my pals no more")
                }
            }
        }
        .environment(\.editMode, $editMode)
        // gimme some proportions
        .padding()
        .frame(minWidth: 500*0.9, minHeight: 500*1.6)
        .alert("End Friendship", isPresented: $showAlert, presenting: coolDudesToBeDeletedCount) { count in
            Button(role: .destructive) {
                endFriendship()
                coolDudesToBeDeletedCount = nil
            } label: {
                Text("End Friendships")
            }
            Button(role: .cancel) {
                coolDudesToBeDeletedCount = nil
            } label: {
                Text("Cancel")
            }
        } message: { _ in
            Text("You're are about to end friendship with at least one cool dude.")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

相关问题