SwiftUI on macOS: Life Cycle and App Delegate source code
This is the Swift source code to accompany the article SwiftUI on macOS: Life Cycle and App Delegate.
AppKit AppDelegate approach
AppDelegate
import Cocoa
@main
class AppDelegate: NSObject, NSApplicationDelegate {
var theTimer: Timer?
var theTimeInterval = 86400.0
var theTolerance = 300.0
func applicationDidFinishLaunching(_ aNotification: Notification) {
let defaults = UserDefaults.standard
dontXProCheck = defaults.bool(forKey: “dontXPR”)
if !dontXProCheck {
let deDys = deDysfunction.init()
if !(deDys.checkAdmin()) {
NSApplication.shared.terminate(self)
}
}
self.theTimeInterval = defaults.double(forKey: “updateCheckInt”)
self.theTolerance = defaults.double(forKey: “updateCheckTol”)
if self.theTolerance < 1.0 {
self.theTolerance = 300.0
}
theSkinner = Skinner()
theTimer = Timer.scheduledTimer(timeInterval: self.theTimeInterval, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true)
theTimer?.tolerance = self.theTolerance
theSkinner?.runChecks()
}
func fireTimer() {
theSkinner?.runChecks()
}
func runSkintChecks(_ sender: NSMenuItem) {
theSkinner?.runChecks()
}
func applicationWillTerminate(_ aNotification: Notification) {
theTimer?.invalidate()
}
SwiftUI with AppDelegate approach
AppDelegate
import Cocoa
import SwiftUI
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
var theTimer: Timer?
var theTimeInterval = 86400.0
var theTolerance = 300.0
@Published var isInited = false
func applicationDidFinishLaunching(_ aNotification: Notification) {
let defaults = UserDefaults.standard
dontXProCheck = defaults.bool(forKey: “dontXPR”)
if !dontXProCheck {
let deDys = deDysfunction.init()
if !(deDys.checkAdmin()) {
dontXProCheck = true
}
}
self.theTimeInterval = defaults.double(forKey: “updateCheckInt”)
self.theTolerance = defaults.double(forKey: “updateCheckTol”)
defaults.set(dontXProCheck, forKey: “dontXPR”)
theSkinner = Skinner()
self.isInited = true
theTimer = Timer.scheduledTimer(timeInterval: self.theTimeInterval, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true)
theTimer?.tolerance = self.theTolerance
}
func fireTimer() {
theSkinner?.runChecks()
}
func applicationWillTerminate(_ aNotification: Notification) {
theTimer?.invalidate()
}
}
SwiftUIApp
import SwiftUI
@main
struct SkintSwiftUIApp: App {
@NSApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
Window(“Skint SwiftUI”, id: “main”) {
ContentView()
}
}
}
ContentView
import SwiftUI
struct ContentView: View {
@EnvironmentObject private var appDelegate: AppDelegate
var body: some View {
if appDelegate.isInited {
VStack {
Text(theSkinner?.theErrors ?? “??”)
.font(.title3)
Text(“Overall error score: (theSkinner?.theErrorScore ?? -1)”)
.font(.title3)
.padding()
}
.background(.indigo)
} else {
VStack {
Text(“Waiting for results…”)
.font(.title)
}
.background(.gray)
}
}
}
Pure SwiftUI approach
SwiftUIApp
import SwiftUI
@main
struct DeclarerTestApp: App {
let theLSkinner = Skinner()
var body: some Scene {
Window(“Declarer”, id: “main”) {
ContentView()
}
}
}
ContentView
import SwiftUI
struct ContentView: View {
var body: some View {
if isInited {
VStack {
Text(theSkinner?.theErrors ?? “??”)
.font(.title3)
Text(theSkinner?.dateText ?? “??”)
.font(.title2)
Text(“Overall error score: (theSkinner?.theErrorScore ?? -1)”)
.font(.title3)
.padding()
}
.background(.windowBackground)
} else {
VStack {
Text(“Waiting for results…”)
.font(.title)
}
.background(.gray)
}
}
}
#Preview {
ContentView()
}
Skinner
import Foundation
import SwiftUI
var theSkinner: Skinner?
var theTimer: Timer?
var theTimeInterval = 86400.0
var theTolerance = 300.0
var isInited = false
@Observable
class Skinner: NSObject {
var theErrors = “”
var theErrorScore = 0
override init() {
super.init()
theSkinner = self
let defaults = UserDefaults.standard
dontXProCheck = defaults.bool(forKey: “dontXPR”)
if !dontXProCheck {
let deDys = deDysfunction.init()
if !(deDys.checkAdmin()) {
dontXProCheck = true
}
}
theTimeInterval = defaults.double(forKey: “updateCheckInt”)
theTolerance = defaults.double(forKey: “updateCheckTol”)
defaults.set(dontXProCheck, forKey: “dontXPR”)
isInited = true
runChecks()
}
func runChecks() {
self.theErrors = “”
self.theErrorScore = 0
theSkinfo = Skinfo.init()
}
}
Scheduler
@Observable
class Sched: NSObject {
var theTimer: Timer?
var theTimeInterval = 1.0
var theCount = 0
func startTimer() {
self.theTimer = Timer.scheduledTimer(withTimeInterval: self.theTimeInterval, repeats: true, block: { _ in
self.fireTimer()
})
}
func stopTimer() {
self.theTimer?.invalidate()
}
func fireTimer() {
self.theCount += 1
}
}
applicationWillTerminate
import SwiftUI
@main
struct SchedulerApp: App {
@Environment(.scenePhase) private var scenePhase
var body: some Scene {
WindowGroup {
ContentView()
}
.onChange(of: scenePhase, initial: false) { oldPhase, newPhase in
if newPhase == .background {
let result = removeTimer()
}
}
}
}
End of code supplement.