SwiftUI,Picker .onChange 触发两次需要更改之前和之后的值

2024-04-04

我遇到了类似于以下帖子的问题.onReceive 触发两次 https://stackoverflow.com/questions/63694325/onreceive-firing-twice-swiftui.

我有一个会触发的选择器.onChange两次。我正在为选择器使用模型数据环境对象。

有没有办法让我获得之前的状态,以便我可以比较new_haveCount价值真的在改变吗?或者更好的是,从一开始就防止双重火灾?

@EnvironmentObject var modelData: ModelData

specifics and specificsFirebase都是结构体。

拣货员代码

            Picker(selection: $modelData.figureArray[figureIndex].specifics.specificsFirebase.new_haveCount,
                   label: Text("  \(modelData.figureArray[figureIndex].specifics.specificsFirebase.new_haveCount) ")) {
                ForEach(0 ..< 20) {
                    Text("\(kSpecificType_Labels[1]) \($0) \(kNewText.lowercased())")
                }
            }
            .onChange(of: modelData.figureArray[figureIndex].specifics.specificsFirebase.new_haveCount) { _ in
                saveSpecifics()
            }

来自苹果开发页面 https://developer.apple.com/documentation/swiftui/view/onchange(of:perform:), .onChange似乎有前后属性。

struct PlayerView : View {
var episode: Episode
@State private var playState: PlayState = .paused

var body: some View {
    VStack {
        Text(episode.title)
        Text(episode.showTitle)
        PlayButton(playState: $playState)
    }
    .onChange(of: playState) { [playState] newState in
        model.playStateDidChange(from: playState, to: newState)
    }
}
}

完整查看如果有帮助的话

import SwiftUI
import Firebase

struct SpecificsEntryView: View {
@EnvironmentObject var modelData: ModelData

let figure: Figure

var figureIndex: Int {
    modelData.figureArray.firstIndex(where: { $0.id == figure.id })!
}

var body: some View {
    HStack(spacing: 4) {
        // new labels
        VStack(alignment: .leading, spacing: 4) {
            ForEach(kSpecificType_Labels, id: \.self) { label in
                Text(label)
                    .frame(maxHeight: .infinity)
                    .padding(.bottom, 2)
                Divider()
            }
        }
        
        // new values
        VStack(alignment: .center, spacing: 4) {
            Text(kNewText)
                .frame(maxHeight: .infinity)
                .padding(.bottom, 2)
            Divider()
            Picker(selection: $modelData.figureArray[figureIndex].specifics.specificsFirebase.new_haveCount,
                   label: Text("  \(modelData.figureArray[figureIndex].specifics.specificsFirebase.new_haveCount) ")) {
                ForEach(0 ..< 20) {
                    Text("\(kSpecificType_Labels[1]) \($0) \(kNewText.lowercased())")
                }
            }
            .onChange(of: modelData.figureArray[figureIndex].specifics.specificsFirebase.new_haveCount) { _ in
                saveSpecifics()
            }
            .frame(maxHeight: .infinity)
            .padding(.bottom, 2)
            .pickerStyle(MenuPickerStyle())
            Divider()
            Picker(selection: $modelData.figureArray[figureIndex].specifics.specificsFirebase.new_wantCount,
                   label: Text("  \(modelData.figureArray[figureIndex].specifics.specificsFirebase.new_wantCount)  ")) {
                ForEach(0 ..< 20) {
                    Text("\(kSpecificType_Labels[2]) \($0) \(kNewText.lowercased())")
                }
            }
            .onChange(of: modelData.figureArray[figureIndex].specifics.specificsFirebase.new_wantCount) { _ in
                saveSpecifics()
            }
            .frame(maxHeight: .infinity)
            .padding(.bottom, 2)
            .pickerStyle(MenuPickerStyle())
            Divider()
            Picker(selection: $modelData.figureArray[figureIndex].specifics.specificsFirebase.new_sellCount,
                   label: Text("  \(modelData.figureArray[figureIndex].specifics.specificsFirebase.new_sellCount)  ")) {
                ForEach(0 ..< 20) {
                    Text("\(kSpecificType_Labels[3]) \($0) \(kNewText.lowercased())")
                }
            }
            .onChange(of: modelData.figureArray[figureIndex].specifics.specificsFirebase.new_sellCount) { _ in
                saveSpecifics()
            }
            .frame(maxHeight: .infinity)
            .padding(.bottom, 2)
            .pickerStyle(MenuPickerStyle())
            Divider()
            Picker(selection: $modelData.figureArray[figureIndex].specifics.specificsFirebase.new_orderCount,
                   label: Text("  \(modelData.figureArray[figureIndex].specifics.specificsFirebase.new_orderCount)  ")) {
                ForEach(0 ..< 20) {
                    Text("\(kSpecificType_Labels[4]) \($0) \(kNewText.lowercased())")
                }
            }
            .onChange(of: modelData.figureArray[figureIndex].specifics.specificsFirebase.new_orderCount) { _ in
                saveSpecifics()
            }
            .frame(maxHeight: .infinity)
            .padding(.bottom, 2)
            .pickerStyle(MenuPickerStyle())
            Divider()
        } // end new vstack

        Divider() // vertical

        // loose values
        VStack(alignment: .center, spacing: 4) {
            Text(kLooseText)
                .frame(maxHeight: .infinity)
                .padding(.bottom, 2)
            Divider()
            Picker(selection: $modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_haveCount,
                   label: Text("  \(modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_haveCount)  ")) {
                ForEach(0 ..< 20) {
                    Text("\(kSpecificType_Labels[1]) \($0) \(kNewText.lowercased())")
                }
            }
            .onChange(of: modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_haveCount) { _ in
                saveSpecifics()
            }
            .frame(maxHeight: .infinity)
            .padding(.bottom, 2)
            .pickerStyle(MenuPickerStyle())
            Divider()
            Picker(selection: $modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_wantCount,
                   label: Text("  \(modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_wantCount)  ")) {
                ForEach(0 ..< 20) {
                    Text("\(kSpecificType_Labels[2]) \($0) \(kNewText.lowercased())")
                }
            }
            .onChange(of: modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_wantCount) { newVal in
                print("\(modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_wantCount) to \(newVal)")
                saveSpecifics()
            }
            .frame(maxHeight: .infinity)
            .padding(.bottom, 2)
            .pickerStyle(MenuPickerStyle())
            Divider()
            Picker(selection: $modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_sellCount,
                   label: Text("  \(modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_sellCount)  ")) {
                ForEach(0 ..< 20) {
                    Text("\(kSpecificType_Labels[3]) \($0) \(kNewText.lowercased())")
                }
            }
            .onChange(of: modelData.figureArray[figureIndex].specifics.specificsFirebase.loose_sellCount) { _ in
                saveSpecifics()
            }
            .frame(maxHeight: .infinity)
            .padding(.bottom, 2)
            .pickerStyle(MenuPickerStyle())
            Divider()
            TextField("Order from", text: $modelData.figureArray[figureIndex].specifics.specificsFirebase.new_orderText,
                      onCommit: {
                        saveSpecifics()
                      })
                .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
                .padding(.bottom, 2)
                .background(Color(.systemGray5))
                .cornerRadius(4)
            Divider()
        } // end loose vstack
    } // end all hstack specifics
    .fixedSize(horizontal: false, vertical: true)
    .font(/*@START_MENU_TOKEN@*/.title/*@END_MENU_TOKEN@*/)
} // end body

// save specifics on update
func saveSpecifics() {

    // Inject Firebase authentication
    let userID = Auth.auth().currentUser?.uid
    modelData.figureArray[figureIndex].specifics.specificsFirebase.saveSpecifics(userID: userID!)
}
}

我遇到了相同的捕获列表语法问题,并通过使用从 EnvironmentObject 变量捕获的值的显式别名来修复它(Xcode 给出了提示)。就像这样:

.onChange(model.someVariable) {[oldValue = model.someVariable] newValue in { ... }

但我的代码仍然导致.onChange开火两次...

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SwiftUI,Picker .onChange 触发两次需要更改之前和之后的值 的相关文章

  • AVPlayerLooper 每次迭代后黑闪

    我正在使用 Apple 的示例代码在UICollectionViewCell背景 我在用着AVPlayerLooper 因为它是同一视频的迭代 我的问题是 当视频结束时 它会显示轻微的黑屏闪烁 也许它正在将视频搜索到0时间 我不确定 这是代
  • GIDSignIn 在提示前指定范围

    我在 iOS 上升级到 GoogleSignIn 6 0 但找不到在登录时指定登录范围的方法 我只能看到一个名为 addScopes 的 API 我可以在基本登录后指定范围 但这会导致两个单独的登录提示 这很奇怪 之前 我们可以简单地指定登
  • Swift 中的 AURenderCallback

    我正在创建一个使用音频单元的应用程序 虽然 Objective C 中有很多代码示例 包括 Apple 自己的 aurioTouch 等 但我正在尝试用 Swift 编写整个代码 我已经能够设置我的 AUGraph 并通过它运行一些音频 但
  • 我应该在我的 iOS Objective-C 项目中使用它吗?

    Xcode 中的 构建设置 中的 Mach O 类型是什么 应该设置什么 它有这些选项 可执行文件 动态库 捆绑包 静态库 可重定位对象文件 自从我将其从可执行文件更改为静态库以来 我遇到了错误 Apple Mach O 链接器错误组 我的
  • 手动设置时间和日期时,iOS 10 中的重复每日本地通知不会被触发?

    我正在尝试通过触发每日通知来测试 iOS 10 中的本地通知 我正在使用以下示例项目 通知UI 演示 https github com appcoda NotificationsUI Demo 该应用程序中有以下代码之一 let calen
  • Itunes Connect 测试飞行公共链接有效性

    苹果最近为试飞版本启用了公共链接功能 我们可以与任何人共享此链接 他可以使用此公共链接安装应用程序 此公共链接背后的构建有效期为 90 天 我的问题是 与用户共享公共链接后 我们可以增加构建的到期时间吗 这样公共链接的有效性就会增加 我们不
  • JavascriptCore:在 JSExport 中将 javascript 函数作为参数传递

    JavascriptCore是iOS7中支持的新框架 我们可以使用 JSExport 协议将 objc 类的部分内容公开给 JavaScript 在javascript中 我尝试将函数作为参数传递 像这样 function getJsonC
  • UITableViewCell 内的 UIPageViewController

    嘿我想问如何在 UITableViewCell 内实现 UIPageViewController 我一直在阅读周围的内容 但到目前为止似乎对任何尝试的人都不起作用 我希望得到一些提示 不需要完整的答案 谢谢 目前还不清楚你到底想做什么 但让
  • “Firebase Storage”,用于图像 - 但是,获取实际的 URL?

    正在将图像发送到 Firebase Storage 系统 sr a StorageReference ie FIRStorageReference let task sr putData data task observe success
  • iOS - iPhone 8、8 Plus 和 iPhone X 的设备平台字符串/内部模型[重复]

    这个问题在这里已经有答案了 是什么设备平台字符串即将推出的 iPhone 8 iPhone 8 Plus 和 iPhone X 列表 根据内部型号识别设备的列表如下 对于斯威夫特 func devicePlatform gt String
  • TestFlight iOS 应用程序 get-task-allow 问题

    我在 ios 的 testflight 中有一个名为 MapItTrackIt 的应用程序 一切都进展顺利 我刚刚更新到 xcode 5 1 我按照以往的方式构建了该应用程序 相同的配置文件和临时证书 这次 当我尝试上传 IPA 文件时 我
  • UITableView 无法一直滚动到底部[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我只是好奇 我做了一些UITable
  • 沙盒测试帐户反复询问 iOS 应用内购买的密码

    我用 Swift 语言开发了一个应用程序 我添加了应用内购买来删除广告 我还创建了一个沙箱帐户来测试 但后来我忘记了这个账户的信息 我不确定信息 密码输入屏幕仍然以闪烁的屏幕显示方式显示 即使我重置设备并重新加载它 也没有任何好处 实际上一
  • UIView 和 UITableView 中的 UITapGestureRecognizer 冲突

    我有一个UIView我在其中添加了一个UITapGestureRecognizer 在该视图中 我还有一个子视图 其中基本上是某种UITableView 问题是为什么不UITableView识别连续点击 而是始终转到点击手势识别器的处理程序
  • 如何让应用更新以吸引人的屏幕形式提供给用户? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我最近在使用 Make My Trip 应用程序 我发现每当我启动应用程序时都会出现一个非常有吸引力的应用程序更新弹出屏幕 它说要更新应用程
  • 如何为移动应用程序创建无密码登录

    我有兴趣在移动应用程序和 API 之间构建某种无密码登录 假设我可以控制两者 动机是必须登录对用户来说非常烦人并且存在安全风险 例如 用户将重复使用现有密码 我希望用户能够立即开始使用该应用程序 我想知道是否有一些可行的技术 例如 在移动设
  • 解包可选值时意外发现 nil - 使用 ALAMOFIRE

    我正在尝试使用 Alamofire 获取 JSON 格式的数据 当我使用一个 URL 时 它工作正常 当我使用另一个 URL 时 我在解包可选值时收到错误 我似乎无法追踪错误来自哪里 我已采取将代码放入 ViewDidLoad 来跟踪错误
  • 方法调用中的插入符[重复]

    这个问题在这里已经有答案了 我正在阅读本教程 并遇到了这行代码 这让我感到困惑 localSearch startWithCompletionHandler MKLocalSearchResponse response NSError er
  • 了解 React Native 中的默认字体大小

    在过去的几个月里 我一直在开发一个 React Native 应用程序 但有些事情总是让我困惑 而我现在正试图弄清楚它的真相 我正在尝试标准化应用程序中的字体大小 正文 标题等 并且正在努力了解 React Native 究竟从哪里获取默认
  • 从基元创建自定义形状

    我正在尝试通过组合原始形状来创建自定义物理形状 目标是创建一个圆形立方体 合适的方法似乎是初始化 形状 变换 我在这里找到的https developer apple com library prerelease ios documenta

随机推荐