仅在冷启动或设置更改时重新加载 table 数据

Reload table data only if cold launch or settings change

我有一个简单的两个选项卡式应用程序,我试图管理它何时或是否 List 从网络重新加载数据。

我想让应用程序仅在以下情况重新加载数据:

我不希望 List 在不切换选项或不切换选项卡的情况下进入 SettingsView() 时重新加载。

// tab view
struct Tabs: View {
 var body: some View {
  TabView {
   ViewOne().tabItem { Label("Settings", systemImage: "gear") }
   ViewTwo().tabItem { Label("List", systemImage: "bag") }
  }
 }
}

// ViewOne
struct ViewOne: View {
 var body: some View {
  Text("View one: Settings")
  // toggles and options here
   .onChange(of: option) { value in
    // do other things here
    UserDefaults.standard.set(true, forKey: "reloadList")
   }
 }
}

// ViewTwo
struct ViewTwo: View {
 var body: some View {
 List(arrayItems) { item in
 }
  .onAppear {
   if( UserDefaults.standard.bool(forKey: "reloadList") ) {
    reloadData()
    UserDefaults.standard.removeObject(forKey: "reloadList")
   }
  }
 }
}

当 运行 应用程序和我切换设置时以上内容有效 - UserDefaults 触发 reloadData() 功能。这也解决了我切换标签页(不更改设置)和不重新加载数据的困境。

但是,由于 table 无法在启动时获取数据 - 冷态或后台,所以我现在用糟糕的用户体验搬起石头砸自己的脚。

我尝试将另一个 UserDefaults.standard.set(true, "coldLaunch") 添加到 Tabs 视图,然后将 reloadList 设置为 true 但直到切换选项卡才触发并且然后再回来。

我也尝试过从 @Environment(\.scenePhase) var scenePhase 设置或触发 reloadData(),但每次启动时都会触发 onAppear

也许我没有想清楚,但我正在努力找出正确的效果流但做不到!

1. cold booting first time (closed state to launch);
2. going from .background to .active state; or
3. toggling a setting in the SettingsView()

对于冷启动: 您可以尝试使用此 https://developer.apple.com/documentation/uikit/uiapplication/1622944-willenterforegroundnotification 或者甚至可能只是将 reload() 放在 viewDidLoad() 中,因为这是在应用程序第一次启动时调用的。

 NotificationCenter.default.addObserver(self, selector:#selector(appToForeground), name: UIApplication.willEnterForegroundNotification, object: nil)

@objc func appToForeground(_ notification: Notification) {
    print("appToForeground ")

}

为了在 SettingsView() 中切换设置,我也在使用通知中心。沿着这些线

在第一个选项卡的 viewDidLoad() 中,您设置了一个观察者

NotificationCenter.default.addObserver(self,
                                       selector: #selector(self.refreshTable),
                                       name: NSNotification.Name(rawValue: "newDataNotif"),
                                       object: nil)

 

    @objc func refreshTable() {
      reloadData()
      self.tableView.reloadData()
    }

然后在您的第二个选项卡上,当您的设置发生变化并且您想在第一个选项卡中重新加载 table 时,这就是您要做的。

例如:

  user.setting.changed = true
  NotificationCenter.default.post(name: NSNotification.Name(rawValue: "newDataNotif"), object: nil)

一旦您的设置发生变化,就会发布此通知,然后您放置在第一个选项卡中的 observer 会收到通知,然后它会调用 @objc func refreshTable() 然后你的 table 就会刷新。

我最终尽我所能解决了这个问题,我想我会把它放在这里供其他可能希望在他们的应用程序中找到执行此操作的方法的用户使用。

在选项卡视图中:

struct Tabs: View {
 @Environment(\.scenePhase) private var scenePhase
 var body: some View {
  TabView {
   ViewOne().tabItem { Label("Settings", systemImage: "gear") }
   ViewTwo().tabItem { Label("List", systemImage: "bag") }
  }

  // -- when the view is active reload the table
  .onChange(of: scenePhase) { phase in
   if( phase == .active ) {
    reloadData()
   }
  }

 }
}

然后在另一个要重新加载的视图中添加 .onAppear 代码:

.onAppear {
 if( UserDefaults.standard.bool(forKey: "reloadList") ) {
  reloadData()
  UserDefaults.standard.removeObject(forKey: "reloadList")
 }
}

其中 UserDefaults.standard.bool(forKey: "reloadList") 设置为 true 来自另一个视图的更改。

存在一些基于应用程序何时变为 inactive 的问题,但由于 iOS 的结构方式,没有任何方法可以在不访问 [的情况下隔离 inactive =17=] 状态也是。