App Lifecycle and System
The app states and launch sequence, background execution and push, deep links and App Groups, permissions, localization, and accessibility.
11 questions
JuniorTheoryVery commonWhat are the five app states, and which callback fires on each key transition?
What are the five app states, and which callback fires on each key transition?
An app is in one of five states — not running, inactive, active, background, suspended. Launch reaches inactive, didBecomeActive makes it active, an interruption returns it to inactive, didEnterBackground backgrounds it, then the system suspends it silently.
Common mistakes
- ✗Thinking a suspended app can still run code in the background
- ✗Expecting a delegate callback when the system suspends or kills the app
- ✗Confusing the brief inactive state with the background state
Follow-up questions
- →What briefly puts a foreground app into the inactive state?
- →Why does no delegate callback fire on the transition to suspended?
JuniorTheoryVery commonWhen you request a permission like camera a second time, what happens — and what does a missing NSUsageDescription cause?
When you request a permission like camera a second time, what happens — and what does a missing NSUsageDescription cause?
The permission alert shows only once — the first request presents it, and a second returns the earlier choice without prompting, so changing a denial means visiting Settings. A missing NSUsageDescription string is fatal — the OS terminates the app the moment you touch that API.
Common mistakes
- ✗Thinking a second request re-prompts the user rather than returning the stored choice
- ✗Believing a missing usage string only returns
nilinstead of crashing - ✗Assuming the user can re-grant a denied permission from inside the app
Follow-up questions
- →How can you send the user to your app's page in the Settings app?
- →Why does iOS crash rather than fail softly on a missing purpose string?
JuniorTheoryCommonWhat can beginBackgroundTask, BGAppRefreshTask, BGProcessingTask, and a background URLSession each run, and for how long?
What can beginBackgroundTask, BGAppRefreshTask, BGProcessingTask, and a background URLSession each run, and for how long?
beginBackgroundTask gives a short finite window as you background. BGAppRefreshTask briefly wakes to refresh content and BGProcessingTask runs longer maintenance while charging. A background URLSession runs transfers in a system daemon that survives suspension.
Common mistakes
- ✗Assuming any of these lets you run arbitrary code indefinitely
- ✗Thinking a background
URLSessionneeds the app to stay alive in memory - ✗Expecting
BGAppRefreshTaskto fire on an exact schedule you choose
Follow-up questions
- →What happens if you never call
endBackgroundTaskbefore the window expires? - →Why does the system, not your code, decide when a
BGAppRefreshTaskruns?
JuniorDesignCommonYou must support opening your app from a link. Compare a custom URL scheme (myapp://…) with a Universal Link — an https:// URL on your domain. Explain what the apple-app-site-association (AASA) file does, how the Associated Domains entitlement ties in, and what happens when the app is not installed. Why is a Universal Link considered safer than a custom scheme?
You must support opening your app from a link. Compare a custom URL scheme (myapp://…) with a Universal Link — an https:// URL on your domain. Explain what the apple-app-site-association (AASA) file does, how the Associated Domains entitlement ties in, and what happens when the app is not installed. Why is a Universal Link considered safer than a custom scheme?
A custom scheme like myapp:// can be registered by any app and fails when yours is not installed. A Universal Link is a real https:// URL — iOS verifies domain ownership via the apple-app-site-association (AASA) file and the Associated Domains entitlement, then opens the app or falls back to the website.
Common mistakes
- ✗Claiming a custom scheme is verified and safe from hijacking
- ✗Thinking a Universal Link needs no server file or entitlement
- ✗Assuming a Universal Link shows an error instead of the website fallback
Follow-up questions
- →Where must the AASA file live and why must it be served over HTTPS?
- →How does iOS behave when two apps register the same custom scheme?
JuniorTheoryCommonWhat happens between the user's tap and didFinishLaunching, and what is SceneDelegate for?
What happens between the user's tap and didFinishLaunching, and what is SceneDelegate for?
The system spawns the process, dyld loads and links the binary's dynamic libraries, then the app delegate is created and didFinishLaunching runs. SceneDelegate owns the per-window UI lifecycle; the app delegate handles process events.
Common mistakes
- ✗Believing no process and library loading happens before
didFinishLaunching - ✗Thinking
SceneDelegatehandles process-level events instead of window UI - ✗Confusing the order in which the app delegate and scene delegate run
Follow-up questions
- →Why does adding many dynamic frameworks slow the pre-
mainlaunch time? - →How does a scene delegate enable more than one window on iPad?
MiddleDesignCommonYour app needs remote push. Walk the full path — how the device obtains a token, the roles of the Apple Push Notification service (APNs) and your server, and how a payload reaches the user. Then contrast a normal user-facing alert, a silent background push (content-available), and a rich notification that shows an image. Finally, explain what is actually delivered when the user has force-quit the app, and why the app's lifecycle state changes what you can rely on. How do you design registration, delivery, and handling so the feature is robust across all three push kinds and across launch states?
Your app needs remote push. Walk the full path — how the device obtains a token, the roles of the Apple Push Notification service (APNs) and your server, and how a payload reaches the user. Then contrast a normal user-facing alert, a silent background push (content-available), and a rich notification that shows an image. Finally, explain what is actually delivered when the user has force-quit the app, and why the app's lifecycle state changes what you can rely on. How do you design registration, delivery, and handling so the feature is robust across all three push kinds and across launch states?
The device gets a token from APNs and hands it to your server; the server sends a payload to APNs, which delivers it. A normal push alerts, a silent content-available push briefly wakes the app to fetch, and a rich push adds media via a service extension. After a force-quit only visible alerts arrive.
Common mistakes
- ✗Thinking the server talks to the device directly instead of through APNs
- ✗Assuming silent pushes still fire after the user force-quits the app
- ✗Believing a rich notification's media is rendered without a service extension
Follow-up questions
- →How does the notification-service extension modify a payload before it is shown?
- →Why can a silent push be throttled or dropped by the system entirely?
MiddleDebuggingCommonFix a Universal Link that lands on the wrong screen after a cold start
Fix a Universal Link that lands on the wrong screen after a cold start
On a cold start iOS delivers the NSUserActivity in willConnectTo via connectionOptions, not through scene(_:continue:). The code handles only the warm continue path, so a cold launch from Messages opens the default screen. Read it on connect and route through the same handler.
Common mistakes
- ✗Handling only the warm
continuepath and ignoringconnectionOptions - ✗Assuming cold and warm launches deliver the activity through the same callback
- ✗Reaching for launch arguments or a server round-trip instead of the scene options
Follow-up questions
- →Why must the router tolerate being asked to navigate before the UI is on screen?
- →How would you handle a link that also arrives as a
URLContexton connect?
JuniorDesignOccasionalYou built a custom tappable control from a plain view. What is the minimum to make it usable with VoiceOver and Dynamic Type — which accessibility label, traits, hints, and font handling do you need?
You built a custom tappable control from a plain view. What is the minimum to make it usable with VoiceOver and Dynamic Type — which accessibility label, traits, hints, and font handling do you need?
Make the view an accessibility element with an accessibilityLabel (what it is) and accessibilityTraits like .button (how it behaves); add an accessibilityHint for the outcome and an accessibilityValue if stateful. For Dynamic Type, use a scalable text style like .body, not a fixed point size, so text grows with the user's setting.
Common mistakes
- ✗Assuming VoiceOver reads a custom view without a label and traits
- ✗Skipping
accessibilityTraits, so the control is not announced as a button - ✗Hardcoding a font size instead of a scalable Dynamic Type text style
Follow-up questions
- →When would you group subviews into one accessibility element versus many?
- →How do you test that the control scales at the largest Dynamic Type size?
JuniorTheoryOccasionalWith String Catalogs and String(localized:), how do plurals and RTL work, and what breaks when German text is 3× longer?
With String Catalogs and String(localized:), how do plurals and RTL work, and what breaks when German text is 3× longer?
String(localized:) resolves a key from a String Catalog at runtime. Plurals use the catalog's CLDR variations (one/few/many/other), not hand-written if counts. RTL mirrors automatically with leading/trailing, not left/right. Long German text clips only if you hardcoded widths.
Common mistakes
- ✗Writing manual
ifplural logic instead of using CLDR categories - ✗Using left/right constraints that do not mirror for RTL languages
- ✗Hardcoding label widths so longer translations clip
Follow-up questions
- →How does a String Catalog store the plural variations for one key?
- →Why prefer a semantic text style over a fixed point size for translated text?
SeniorTheoryOccasionalHow do you tell memory pressure, a watchdog timeout, and an expired background task apart in a crash report?
How do you tell memory pressure, a watchdog timeout, and an expired background task apart in a crash report?
Memory pressure appears as a Jetsam event, not a normal crash — a memory report with a per-process-limit reason and no backtrace. A watchdog kill for a missed lifecycle deadline carries code 0x8badf00d. An expired background task terminates with 0xdead10cc. The termination reason and code tell the three apart.
Common mistakes
- ✗Expecting a memory-pressure kill to look like a normal crash with a backtrace
- ✗Confusing the
0x8badf00dwatchdog code with the0xdead10ccbackground-task code - ✗Assuming an expired background task leaves no trace in the report
Follow-up questions
- →Why does a Jetsam report list memory footprint instead of a crashed thread?
- →What resource is the
0xdead10cctermination usually protecting against?