swiftUI:在更改设置后更新文本

swiftUI:在更改设置后更新文本,swiftui,Swiftui,[编辑(1)以反映问题:。 [编辑(2):完全删除EnvironmentObject,应用程序现在可以工作了!不理解为什么正文会刷新,因为没有@State变量被修改…文本末尾的代码] 我正在编写一个应用程序,在某个时候,它会根据一组规则显示一些与2个数组的内容相关的文本。这些规则可以根据用户的偏好在设置视图中设置。 因此,当用户更改他希望在设置中应用的规则时,需要重新评估该文本。 当然,事情并没有那么容易。 我在主ContentView中将设置视图显示为模态,当我取消该模态时,ContentVi

[编辑(1)以反映问题:。
[编辑(2):完全删除EnvironmentObject,应用程序现在可以工作了!不理解为什么正文会刷新,因为没有@State变量被修改…文本末尾的代码]

我正在编写一个应用程序,在某个时候,它会根据一组规则显示一些与2个数组的内容相关的文本。这些规则可以根据用户的偏好在设置视图中设置。 因此,当用户更改他希望在设置中应用的规则时,需要重新评估该文本。
当然,事情并没有那么容易。
我在主ContentView中将设置视图显示为模态,当我取消该模态时,ContentView的主体不会被重新绘制

我用@Published vars创建了一个EnvironmentObject,以跟踪所有用户首选项(也写入用户默认值),并将该@EnvironmentObject与我的ContentView和SettingsView共享,希望作为一个observedObject,它的更改将触发我的ContentView的刷新

不是这样

有什么办法可以帮我解决这个问题吗?任何指点都将不胜感激(再次!)

具有以下体系结构:

一个
appState
EnvironmentObject,
一种
ContentView
,根据中设置的某些用户首选项显示一组文本 A
设置视图

用户默认值在
AppDelegate
中初始化

谢谢你在这方面的帮助

内容视图:


import SwiftUI
struct ContentView: View {

  @State var modalIsPresented = false // The "settingsView" modally presented as a sheet

  @State private var modalViewCaller = 0 // This triggers the appropriate modal (only one in this example)

    var body: some View {

        NavigationView {
            VStack {
                Spacer()
                    VStack {
                    Text(generateStrings().text1)
                        .foregroundColor(Color(UIColor.systemGreen))
                    Text(generateStrings().text2)
                    } // end of VStack
                        .frame(maxWidth: .infinity, alignment: .center)
                        .lineLimit(nil) // allows unlimited lines
                        .padding(.all)
                Spacer()
            } // END of main VStack
            .onAppear() {
                self.modalViewCaller = 0
            }
            .navigationBarTitle("Test app", displayMode: .inline)
            .navigationBarItems(leading: (
                Button(action: {
                    self.modalViewCaller = 6 // SettingsView
                    self.modalIsPresented = true
                }
                    ) {
                        Image(systemName: "gear")
                            .imageScale(.large)
                     }
            ))
        } // END of NavigationView
        .sheet(isPresented: $modalIsPresented, content: sheetContent)
        .navigationViewStyle(StackNavigationViewStyle()) // This avoids dual column on iPad

    } // END of var body: some View

  // MARK: @ViewBuilder func sheetContent() :

    @ViewBuilder func sheetContent() -> some View {

        if modalViewCaller == 6 {
            SettingsView()
            }
    } // END of func sheetContent


    // MARK: generateStrings() : -

    func generateStrings() -> (text1: String, text2: String, recapText: String, isHappy: Bool) { // minimumNumberOfEventsCheck

        var myBool = false
        var aString = "" // The text 1 string
        var bString = "" // The text 2 string
        var cString = "" // The recap string

        if UserDefaults.standard.bool(forKey: kmultiRules) { // The user chose the dual rules option
            let ruleSet = UserDefaults.standard.integer(forKey: kruleSelection) + 1
            aString = "User chose 2 rules option"
            bString = "User chose rule set # \(ruleSet)"
            myBool = true
            print("isDualRules true loop : generateStrings was called at \(Date().debugDescription)")
            cString = "Dual rules option, user chose rule set nb \(ruleSet)"
        }
            else // The user chose the single rule option
        {
            aString = "User chose single rule option"
            bString = "User had no choice : there is only one set of rules !"
            myBool = false
            print("isDualRules false loop : generateStrings was called at \(Date().debugDescription)")
            cString = "Single rule option, user chose nothing."
        }


            return (aString, bString, cString, myBool)
    } // End of func generatestrings() -> String

}

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

    }
}

设置视图:

import SwiftUI
import UIKit

struct SettingsView: View {

    @Environment(\.presentationMode) var presentationMode // in order to dismiss the Sheet

    @State public var multiRules = UserDefaults.standard.bool(forKey: kmultiRules)

    @State private var ruleSelection = UserDefaults.standard.integer(forKey: kruleSelection) // 0 is rule 1, 1 is rule 2


    var body: some View {

        NavigationView {
            List {

                Toggle(isOn: $multiRules)
                {
                    Text("more than one rule ?")
                }
                .padding(.horizontal)

                if multiRules {
                            Picker("", selection: $ruleSelection){
                                Text("rules 1").tag(0)
                                Text("rules 2").tag(1)
                            }.pickerStyle(SegmentedPickerStyle())
                            .padding(.horizontal)
                        }

            } // End of List
            .navigationBarItems(
                leading:
                Button("Done") {
                        self.saveDefaults() // We try to save once more if needed
                        self.presentationMode.wrappedValue.dismiss() // This dismisses the view
                }
            )
                .navigationBarTitle("Settings", displayMode: .inline)
        } // END of Navigation view
    } // END of some View


    func saveDefaults() {
        UserDefaults.standard.set(multiRules, forKey: kmultiRules)
        UserDefaults.standard.set(ruleSelection, forKey: kruleSelection)
    }    
}



// MARK: Preview struct

struct SettingsView_Previews: PreviewProvider {
    static var previews: some View {

        return SettingsView()
    }
}

常量.swift文件:

import Foundation
import SwiftUI

let kmultiRules = "two rules"
let kruleSelection = "rules selection"
let kappStateChanged = "appStateChanged"

AppDelegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        UserDefaults.standard.register(defaults: [ // We initialize the UserDefaults
        "two rules": false,
        "rules selection": 0, // 0 is ruel 1, 1 is rule 2
        "appStateChanged": false
        ])

        return true
    }

如果在两个视图中有一个共享的@EnvironmentObject和@Published属性,如果从一个视图中更改此类属性,则另一个视图将重新执行body属性,并且该视图将更新

创建简单的独立示例确实很有帮助——不仅是为了在这里提问,也为了获得更深入的理解/了解为什么它在复杂情况下不起作用

例如:

导入快捷界面
类文本设置:ObservableObject{
@已发布变量计数:Int=1
}
结构文本设置视图:视图{
@环境对象变量设置:文本设置
var body:一些观点{
形式{
选择器(选择:$settings.count,标签:
文本(“文本重复计数”))
{
ForEach(数组(1…5),id:\.self){中的值
文本(字符串(值)).tag(值)
}
}
}
}
}
结构文本和设置示例视图:视图{
@环境对象变量设置:文本设置
var body:一些观点{
文本(字符串(重复“Hello”,计数:Int(settings.count)))
.navigationBarItems(尾部:NavigationLink(“设置”,目标:TextSettingsView()))
}
}
带有设置示例视图的结构文本\u预览:预览提供程序{
静态var预览:一些视图{
导航视图{
TextWithSettingExampleView()
}
.environmentObject(TextSettings())
}
}

我不确定自己是否完全理解这个问题,但我认为可能存在类似的问题,即当从模式触发更改时,我从未让contentview反映观察对象中的更新。我通过在我观察到的对象中触发一个动作来解决/破解了这个问题,当时我忽略了模态,如下所示:

struct ContentView: View {
//
@State var isPresentingModal = false
var body: some View {
//
.sheet(isPresented: self.$isPresentingModal) {
                        PresentedModalView()
                            .onDisappear {
                                //Do something here
                         }
                       }
                     }
                   }

让我们从问题的演示代码开始…阅读并记录这个和这个。这不是一个“我们免费为您编写代码”的平台,而是一个“我们帮助您完成您迄今为止所获得的代码”的平台。好吧,我从来没有认为这个平台像是一个“免费代码”的场所。我总是提供清晰的代码来说明我的任何问题。我只是在这里找一个指针。。。我的应用程序的代码现在太长了,我很难提取一个工作框架来提供代码。明天将调查通知中心,这似乎对我的问题很有希望。尝试了通知中心的方法,在OnDiss中触发它,正如Olaf建议的那样,没有乐趣。。。我最大限度地简化了应用程序,并将其发布在GitHub上,如果有人有时间花在这上面。。。谢谢与onAppear相反,onDisappear总是被触发的好主意。但是文本仍然不会更新!我用一个链接编辑了我的问题,该链接指向我通过尽可能简化现有应用程序而创建的示例应用程序:浏览一下您的项目,您是否尝试过在内容视图中从onDisappear调用“self.appState.updateValues()”?只是胡乱猜测。是的,我猜了,不高兴。。。我完全解构了我的应用程序,为了摆脱环境对象,我将generateStrings func中的if参数更改为direct UserDefaults值,现在,我的ContentView的主体被刷新,即使没有修改@State变量!简言之,这个应用程序可以工作,但我不知道为什么。。。将用我的代码编辑问题…感谢您的洞察力Ralf,我更新了我的问题:我构建了一个示例项目(),但仍然无法使其工作。我正在更改环境对象的@Published属性,未成功。。。