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()
}

@objc func fireTimer() {
theSkinner?.runChecks()
}

@IBAction 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
}

@objc 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()
}

@objc 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.