Add Home Screen quick actions
At a glance
| Item |
Summary |
| Purpose |
Publishes favorite contacts as dynamic Home Screen actions and routes selected actions into the correct UI. |
| App architecture |
SceneDelegate is the quick-action coordinator; it translates scene callbacks into navigation over a small shared contact store. |
| Main patterns |
Scene lifecycle adapter, shared in-memory store, value model, storyboard navigation, and framework delegates. |
| Project style |
One UIKit target with lifecycle/controllers at the root and contact data under Models/. |
Project structure
HomeScreenQuickActions/
├── AppDelegate.swift
├── SceneDelegate.swift
├── ContactsViewController.swift
├── ContactDetailViewController.swift
├── Models/
│ ├── Contact.swift
│ └── ContactsData.swift
└── Base.lproj/Main.storyboard
Structure observations
- Quick-action production and consumption live together in
SceneDelegate because both are scene-lifecycle operations.
- Table/detail controllers read and edit the same in-memory contact store.
Contact owns action-safe value conversion in a focused extension.
Overall architecture
flowchart LR
Scene["SceneDelegate"] --> Store["ContactsData.shared"]
Store --> Contact["Contact values"]
Scene --> Actions["UIApplication.shortcutItems"]
Actions -. selected item .-> Scene
Scene --> Navigation["UINavigationController"]
Navigation --> Detail["ContactDetailViewController"]
List["ContactsViewController"] --> Store
Detail --> Store
Reference code
HomeScreenQuickActions/SceneDelegate.swift:93 — the scene converts current favorites into dynamic shortcut items before resigning active.
func sceneWillResignActive(_ scene: UIScene) {
let application = UIApplication.shared
application.shortcutItems = ContactsData.shared.favoriteContacts.map { contact in
UIApplicationShortcutItem(type: ActionType.favoriteAction.rawValue,
localizedTitle: contact.name,
localizedSubtitle: contact.email,
icon: UIApplicationShortcutIcon(systemImageName: "star.fill"),
userInfo: contact.quickActionUserInfo)
}
}
Interpretation
The app has two entry paths into the same feature: normal table navigation and a scene-delivered shortcut. SceneDelegate resolves shortcut payloads to model identity, then performs the navigation that only the scene/window layer can see.
Ownership and state
classDiagram
SceneDelegate o-- UIWindow : framework supplies
SceneDelegate o-- UIApplicationShortcutItem : retains until active
ContactsData *-- Contact : stores values
ContactDetailViewController o-- Contact : edits a value copy
ContactsViewController --> ContactsData : reads shared store
ContactDetailViewController --> ContactsData : writes shared store
Ownership evidence
HomeScreenQuickActions/Models/ContactsData.swift:10 — a mutable value-type singleton is the sample’s process-local source of contacts.
struct ContactsData {
static var shared = ContactsData()
var contacts = [
Contact(name: "John Doe", email: "john@example.com", favorite: true),
Contact(name: "Jane Doe", email: "jane@example.com", favorite: true)
]
}
| Owner |
Object or state |
Relationship |
Mutation authority |
| UIKit scene lifecycle |
SceneDelegate and window |
UIKit creates the delegate and supplies the window |
Scene callback methods |
SceneDelegate |
savedShortCutItem |
Temporarily retains a launch-time shortcut |
Scene lifecycle methods |
ContactsData.shared |
Contact array |
Global value store |
Any same-module caller; updates go through updateContact in this sample |
| Detail controller |
Current Contact and outlets |
Receives a contact value and owns edit UI |
Text-field/switch callbacks, then store update |
Class and protocol design
| Type or protocol |
Responsibility |
Depends on |
SceneDelegate / UIWindowSceneDelegate |
Publish, receive, decode, and route quick actions |
UIApplication, window navigation, contact store |
ContactsViewController |
Display contacts and pass the selected value to detail |
UITableViewController, shared store |
ContactDetailViewController / UITextFieldDelegate |
Edit one contact and commit changes |
Form outlets, shared store |
ContactsData |
Query favorites/identity and replace edited values |
[Contact] |
Contact |
Hold stable identity and encode shortcut user info |
UUID, secure-coding dictionary |
There is no app-defined protocol abstraction. Protocol use is limited to UIKit lifecycle and input callbacks; the model collaboration is concrete.
Access control
| Symbol |
Access |
Verified effect |
Likely rationale |
| App types and properties |
implicit internal |
All target files can reach the scene, controllers, and model store. |
Small teaching app favors direct collaboration over an exported API. |
ContactsData.shared and contacts |
implicit internal mutable state |
Any same-module code may replace the store or array. |
Convenience for a sample; a production store would normally narrow mutation. |
| Controller outlets |
implicit internal |
Storyboard wiring and target code can access them. |
Interface Builder integration. |
No private / fileprivate declarations |
verified absence |
The source establishes no lexical privacy boundary. |
Simplicity, not evidence that broad access is architecturally required. |
Reference code
HomeScreenQuickActions/ContactDetailViewController.swift:10 — the controller, injected model value, and outlets all use the module default.
class ContactDetailViewController: UITableViewController {
var contact: Contact?
@IBOutlet var nameTextField: UITextField!
@IBOutlet var emailTextField: UITextField!
@IBOutlet var favoriteSwitch: UISwitch!
}
Logic ownership and placement
| Logic |
Owning type or file |
Placement rationale |
| Shortcut publication and routing |
SceneDelegate |
Requires scene/window lifecycle and navigation context. |
| Favorite filtering, identifier lookup, replacement |
ContactsData |
Collection-level model operations. |
| Secure shortcut payload conversion |
Contact extension |
Transformation belongs beside the value it represents. |
| Contact list presentation |
ContactsViewController |
Table data-source concern. |
| Editing and commit triggers |
ContactDetailViewController |
Form and text-field lifecycle concern. |
Design patterns
| Pattern |
Source evidence |
Purpose or tradeoff |
| Scene lifecycle adapter |
HomeScreenQuickActions/SceneDelegate.swift:25 |
Handles both cold-launch and already-connected shortcut delivery. |
| Shared in-memory store |
HomeScreenQuickActions/Models/ContactsData.swift:13 |
Gives all screens and the scene one data source, at the cost of global mutable state. |
| Value model |
HomeScreenQuickActions/Models/Contact.swift:10 |
Hashable/Codable contact values carry stable identifiers. |
| Framework delegate |
HomeScreenQuickActions/ContactDetailViewController.swift:43 |
Converts text-field completion into model updates. |
Naming conventions
- Lifecycle and screen roles use
Delegate and ViewController suffixes.
ActionType cases end in Action; the raw values match shortcut type identifiers.
favoriteContacts is a derived noun, while updateContact and handleShortCutItem are commands.
- Model files sit under
Models/; controller files match their primary type.
Architecture takeaways
- Route external launch intents at the scene boundary, where window navigation is available.
- Store a cold-launch shortcut until the scene becomes active; handle connected-scene shortcuts immediately.
- Put shortcut payload encoding beside the domain value and decode back to stable identity.
- Treat the sample’s globally mutable value store as a convenience, not a production access-control model.
Source map
| Source file |
Relevant symbols |
HomeScreenQuickActions/SceneDelegate.swift |
ActionType, shortcut publication and routing |
HomeScreenQuickActions/ContactsViewController.swift |
Contact list and segue injection |
HomeScreenQuickActions/ContactDetailViewController.swift |
Editing and store updates |
HomeScreenQuickActions/Models/ContactsData.swift |
Shared contact collection |
HomeScreenQuickActions/Models/Contact.swift |
Contact identity and shortcut user info |