我正在编写一个 SwiftUI 应用程序,我希望它定期从服务器刷新数据:
下面是我到目前为止的代码。
首次在 SwiftUI 应用程序中打开应用程序时,触发此更新代码的最佳方法是什么?添加观察者是否是onAppear在应用程序进入前台时触发更新的好习惯?(这是应用程序中的唯一视图)
class InfoStore {
var lastValueCheck: Date = .distantPast
}
struct ContentView : View {
var infoStore: InfoStore
private func updateValueFromServer() {
// request updated value from the server
// if the request is successful, store the new value
currentValue = 500
UserDefaults.cachedValue = 500
// hardcoded for this example
infoStore.lastValueCheck = Date()
}
private func updateValueIfOld() {
let fiveMinutesAgo: Date = Date(timeIntervalSinceNow: (-5 * 60))
if infoStore.lastValueCheck < fiveMinutesAgo {
updateValueFromServer()
}
}
@State var currentValue: Int = 100
var body: some View {
Text("\(currentValue)")
.font(.largeTitle)
.onAppear {
NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification,
object: nil,
queue: .main) { (notification) in
self.updateValueIfOld()
}
}
}
}
extension UserDefaults {
private struct Keys {
static let cachedValue = "cachedValue"
}
static var cachedValue: Int {
get {
return standard.value(forKey: Keys.cachedValue) as? Int ?? 0
}
set {
standard.set(newValue, forKey: Keys.cachedValue)
}
}
}
Run Code Online (Sandbox Code Playgroud)
1)关于第一点(应用程序首先打开):可能获得你想要的最好方法是使用DataBinding和ObservableObjects提取视图之外的逻辑(如MVVM建议)。我尽可能少地更改您的代码,以便向您展示我的意思:
import SwiftUI
class ViewModel: ObservableObject {
@Published var currentValue = -1
private var lastValueCheck = Date.distantPast
init() {
updateValueFromServer()
}
func updateValueIfOld() {
let fiveMinutesAgo: Date = Date(timeIntervalSinceNow: (-5 * 60))
if lastValueCheck < fiveMinutesAgo {
updateValueFromServer()
}
}
private func updateValueFromServer() {
// request updated value from the server
// if the request is successful, store the new value
currentValue = 500
UserDefaults.cachedValue = 500
// hardcoded for this example
lastValueCheck = Date()
}
}
struct ContentView : View {
@ObservedObject var viewModel: ViewModel
var body: some View {
Text("\(viewModel.currentValue)")
.font(.largeTitle)
.onAppear {
NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification,
object: nil,
queue: .main) { (notification) in
self.viewModel.updateValueIfOld()
}
}
}
}
extension UserDefaults {
private struct Keys {
static let cachedValue = "cachedValue"
}
static var cachedValue: Int {
get {
return standard.value(forKey: Keys.cachedValue) as? Int ?? 0
}
set {
standard.set(newValue, forKey: Keys.cachedValue)
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(viewModel: ViewModel())
}
}
#endif
Run Code Online (Sandbox Code Playgroud)
这样,一旦ViewModel创建,currentValue就会更新。此外,每次currentValue服务器调用更改时,都会自动为您重新创建 UI。请注意,您必须以sceneDelegate这种方式修改:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: ContentView(viewModel: ViewModel()))
self.window = window
window.makeKeyAndVisible()
}
}
Run Code Online (Sandbox Code Playgroud)
2)关于第二点(应用程序进入前台):你在这里应该小心,因为你多次注册观察者(每次onAppear被触发)。根据您的需要,您应该决定:
onDisappear(这很常见)在任何情况下,执行以下操作都是一个好习惯:
deinit {
}
Run Code Online (Sandbox Code Playgroud)
方法并最终移除观察者。
| 归档时间: |
|
| 查看次数: |
1677 次 |
| 最近记录: |