Skip to main content

Command Palette

Search for a command to run...

SwiftUI应用程序初始化与状态管理

Published
1 min read
SwiftUI应用程序初始化与状态管理

如果在应用启动时决定去完成一些操作,或是应用程序的状态发生一些改变,比如切入后台、重新激活时想要完成一些操作,在SwiftUI里将如何进行处理呢?我在英语小助手里就需要在启动时同步服务器数据到本地的数据库,另外在程序后台重新激活时再次尝试同步,所以在这里记录一张小纸条。

相关文档

从iOS14开始,SwiftUI在启动时可以使用App来进行应用初始化和管理。Apple官方给出了App的文档。在 App Structure and Behavior文档中 中就提到你可以使用 Scenes 来说明用户界面(通常就是我们写的View)了,同时也通过Scene来触发由系统管理的生命周期。

在App中管理状态处理

我的数据同步需要在App启动和从后台唤醒时进行,而且它的执行使用了async的异步调用,所以我特别 准备了一个ViewModel 来帮助我完成这个工作:

class LearnEnglishHelperViewModel:ObservableObject{
    private var realmController : RealmController

    @Published var isLoading = true

    init(){
        realmController = RealmController.shared
        Task{
            await fetchData()
        }
    }

    func fetchData() async{
        isLoading = true
        await realmController.fetchData()
        isLoading = false
    }
}

它的async的fetchData函数就是一个与服务器进行同步数据的异步函数了。它在ViewModel init时就会被执行一次,是因为在App启动时就会初始化这个ViewModel了(https://github.com/HDCodePractice/EnglishHelperApp/blob/main/LearnEnglishHelperApp/LearnEnglishHelperApp/LearnEnglishHelperAppApp.swift):

import SwiftUI

@main
struct LearnEnglishHelperAppApp: App {
    @StateObject var vm = LearnEnglishHelperViewModel()
    @Environment(\.scenePhase) var scenePhase

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(vm)
        }
        .onChange(of: scenePhase) { phase in
            switch phase{
            case .active:
                print("app active")
                Task{
                    if vm.isLoading == false{
                        await vm.fetchData()
                    }
                }
            case .inactive:
                print("app inactive")
            case .background:
                print("app background")
            default:
                print("app unknow status")
            }
        }
    }
}

所以,只要App启动时,会init @stateObject var vm,所以也就触发了第一次的数据同步。之后通过scenePhash环境变量,只需要在Scene的.onChange里识别应用状态的变化即可。这里我只对active状态做了处理,也就是App在active状态时看看上次同步数据有没有完成,如果完成了,就再做一次数据同步。

在SwiftUI里对应用状态进行处理

其实我们在一个View里也可以使用相同的方法对应用状态发生变化进行处理。这里有一个示例:

import SwiftUI

struct ContentView: View {

    @Environment(\.scenePhase) private var scenePhase

    var body: some View {
        Text("Hello, world!")
            .padding()
            .onChange(of: scenePhase, perform: { value in
                if value == .active {
                    print("app active")
                }
            })
    }
}

接下来你可以对App状态进行你自己的管理了。

More from this blog

Https 本地服务器小纸条

最近想要尝试一下Telegram mini app,在调试时需要使用https的服务。试来试去发现在Mac下完成一个简单的HTTPS服务器还是需要点奇奇怪怪的工具的。但是整体来讲非常简单。 准备证书 主要会使用mkcert来创建证书。首先安装mkcert。 brew install mkcert brew install nss # if use Firefox 将mkcert加入到本地root CA。 mkcert -install 生成证书 本地调试可以使用localhost或127.0...

Feb 21, 20241 min read
Https 本地服务器小纸条

macOS中使用Docker发布一个python项目的小纸条

最近写了一个Telegram Bot,它可以使用语音和文字与GPT进行交互,成为了我日常重度使用的工具。从练习英语的听说读,到日常的搜索使用上都让我有了不少收获。终于,日常跑在我笔记本上的日子就要过去了,我需要它能日常跑在我的服务器上,所以准备使用Docker整个image,使得我日常的更新和服务器的迁移更为简单些。所以写下这个小纸条,方便以后自己回来查看。 安装Docker 使用Homebrew安装简单方便: brew install --cask docker Homebrew会视你的机器...

Mar 10, 20233 min read
macOS中使用Docker发布一个python项目的小纸条

老房东的纸条箱

39 posts