20 Open a Project

Start a new app project by:

  • opening Xcode and choosing create a new project
  • select a single view iOS app, choose a project name
  • select Swift as the language and SwiftUI as the user interface

Follow https://developer.apple.com/tutorials/swiftui for tutorials to help get started. I did and these notes are things I distilled out of that experience and want to remember.

Data Models

Apple approaches from the UI side, however I really like to start by thinking about data and how to organize it. Xcode creates an application framework with no data models at all. Start by choosing File / New / Group to create groups to organize your files, maybe Screens and Subviews to hold views and put the code files in the application root group. Then click on the application folder and choose File / New / File to create a Swift File with a name like “UserSettings.swift”.

  • define your global structs, classes, and variables in UserData.swift or somewhere else global so they can be published to views and modified by external code like a location manager.
    • in Mapper the class UserSettings follows the ObservableObject protocol, so it can be attached as an environment element.  The instance userSettings is a global variable that can have values assigned by any function, anywhere, e.g. in the location manager.
    • in SceneDelegate.swift under willConnectTo session: the userSettings instance is attached to ContentView as an environment object.
      let contentView = ContentView().environmentObject(userSettings)
    • in ContentView and subsidiary views, the name settings is assigned to the environment object for local referencing. This makes me think there can only be one object of a given class in the environment.
      @EnvironmentObject var settings: UserSettings
    • in previews, be sure to include the environment so the preview has some data to work with.  This doesn’t need to be done explicitly when views are called as subsidiary views within a parent view — they inherit the environment from the parent.
      ContentView().environmentObject(UserSettings())
  • structs are value types, so assignment moves the current value into another copy of the object
  • classes are reference types, so assignment provides another pointer to the same storage space

Now you are ready to start defining some data and some logic for manipulating and displaying that data. When you change the value of a published environment variable, all the views that depend on it will update automatically.

Identifiable Objects for Lists

In order to take advantage of the SwiftUI list capabilities, the items in your list need to follow the Identifiable protocol. An easy way to do that is to start with a struct that includes a constant component named id of type UUID with each instance of the struct having a unique id value. ( let id = UUID( ) )

Timers to Make things Happen

https://www.hackingwithswift.com/articles/117/the-ultimate-guide-to-timer has it all pretty well. Embedding a timer in a view like https://medium.com/better-programming/make-a-simple-countdown-with-timer-and-swiftui-3ce355b54986 creates problems with previews. Consider declaring some timers as global so you can update them or invalidate them from anywhere. This code in UserSettings.swift

// keeps the dateNow up to date in the userSettings -- set in SceneDelegate
var fastTimer = Timer()

func fastTimerAction(){
    userSettings.dateNow = Date()
}

is set in motion at the start of execution by this code in SceneDelegate.swift

fastTimer = Timer.scheduledTimer(withTimeInterval: 0.03, repeats: true) {_ in
    fastTimerAction()
}

This scheduled timer will call fastTimerAction() to update the value of dateNow, forcing an update in any views that depend on it. You need to make the assignment in code that will run after execution begins, like in SceneDelegate. This fast timer is good for keeping real time displays up to date. Slower timers can be used to generate events independent of the user.

Background Processing for Location Data

Set the application to allow background location updates under signing and capabilities.

Make sure the authorization request strings are in Info.plist

Set the location manager allowsBackgroundLocationUpdates = true and pausesLocationUpdatesAutomatically = false

Consider using region monitoring to be sure the app is relaunched or brought to foreground automatically.

An error will show up in debug saying “Can't end BackgroundTask: no background task exists with identifier 1 (0x1), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.” when you switch out of the app, but it seems to be harmless.

License

Icon for the Creative Commons Attribution-ShareAlike 4.0 International License

Rick's Remote and Online Teaching Notes Copyright © 2019 by Rick Sellens is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License, except where otherwise noted.

Share This Book