iOS / Swift
iOS development means building iPhone and iPad apps in Swift, a compiled language that frees memory by counting references instead of running a garbage collector. That one choice explains the platform’s most common silent bug — two objects keeping each other alive forever — and most of what a native iOS team designs on purpose. The page opens with sixteen references an iOS app holds and what releases each one, then covers reference counting, SwiftUI against UIKit and who owns the state, Swift concurrency up to Swift 6.4, review, TestFlight and the seven-day phased release, Apple’s 2026 deadlines, five documented cases, and where it degrades.
- Current version
- Swift 6.4 · Xcode 27 · iOS 27, Sep 2026
- Memory
- Counted, not collected — no pauses, no cycle detection
- Release
- Every build reviewed; 90% within 24 hours
Who keeps this object alive — sixteen references an iOS app holds
In Swift an object — an instance of a class — lives exactly as long as something holds a strong reference to it. When the last one goes, the object is freed on the spot. Nothing comes along later to find the objects nobody can reach any more, the way a garbage collectorfrees memory nobody usesThe part of a runtime that finds objects nothing refers to any more and frees their memory, so the program never frees it by hand. The price is extra memory and work the program does not schedule — pauses, short or long depending on the collector.Full article →All terms does on Android or in Java. So a screen that should have been freed and was not is never a crash. It is memory that grows, a timer that keeps firing for a screen nobody sees, a network callback that updates a view that is gone. The useful question about any reference is therefore not “is this a leak?”. It is “who holds whom, and what makes them let go?”. Here are sixteen references an iOS app holds every day. Later sections cite the rows by number.
| # | The reference | Who holds whom | What happens | The fix |
|---|---|---|---|---|
| 1 | A local constant — let parser = Parser() inside a function | The function’s scope holds the object | Freed when the function returns | Nothing |
| 2 | A struct, an enum, a String or an Array | Values are copied, not shared; a value has no reference count of its own | Lives as long as the variable that holds it; copy-on-write keeps the copies cheap | Nothing — which is why most Swift types are values |
| 3 | A non-escaping closure — map, filter, sorted(by:) | The closure exists only during the call | Cannot outlive the call, so it cannot form a cycle | Nothing; [weak self] here is noise |
| 4 | An escaping closure that self does not store — DispatchQueue.main.async, UIView.animate | The queue or UIKit holds the closure; the closure holds self | Keeps self alive until it has run, then lets go — a delay, not a leak | Nothing, unless the delay matters |
| 5 | Task { await self.load() } that finishes | The task holds self until it completes | Same as row 4: released when the work ends | Cancel it when the screen goes away, so the work stops too |
| 6 | A delegate declared var delegate: Delegate? | The child holds its owner while the owner holds the child | A cycle: neither is ever freed | weak var delegate, with a class-only (AnyObject) protocol |
| 7 | A closure stored on self that uses self — onTap = { self.close() } | self → closure → self | A cycle | [weak self] in the capture list |
| 8 | A child with a strong parent property | parent → child → parent | A cycle | weak var parent |
| 9 | A Combine sink stored in self.cancellables that uses self | self → set → subscription → closure → self | A cycle: the subscription lives as long as self and keeps self alive | [weak self], or assign(to: &$property), which does not retain |
| 10 | A block-based NotificationCenter observer whose block uses self | The center holds the token, the token holds the block, the block holds self | self lives until the observer is removed | [weak self] in the block, and remove the token |
| 11 | A stored Task that loops forever — for await over notifications — and uses self | self → task → closure → self | A cycle that never ends by itself; cancelling it in deinit cannot work, because deinit never runs | Cancel it when the screen disappears; in SwiftUI use .task, which is cancelled with the view |
| 12 | Timer.scheduledTimer(timeInterval: 1, target: self, …) | The run loop holds the timer; the timer holds its target | self lives until invalidate() — Apple’s documentation says so | invalidate() when the screen disappears; a block timer with [weak self] |
| 13 | CADisplayLink(target: self, …) for frame-by-frame drawing | The display link retains its target; the run loop holds the link | As row 12 | invalidate(), or a small weak proxy object as the target |
| 14 | URLSession(configuration:delegate:delegateQueue:) | The session keeps a strong reference to its delegate | Leaks until the app exits, unless the session is invalidated | finishTasksAndInvalidate(), or one long-lived session for the whole app |
| 15 | WKUserContentController.add(self, name:) — a JavaScript message handler | The web view’s content controller holds the handler strongly | The screen that owns the web view is never freed | removeScriptMessageHandler(forName:) when the screen disappears, or a weak proxy |
| 16 | A singleton or a static cache holding a view controller, a view, or a closure that captures one | The cache lives as long as the app | Not a cycle — the object simply never becomes unreachable | Keep screens out of long-lived objects; store ids and data, not views |
Reference counting: what Swift does instead of a garbage collector
Automatic Reference Counting, ARC, is simple to state. Every class instance carries a count of the strong references that point at it. The compiler inserts an increment wherever a reference is stored and a decrement wherever one goes away, so you never write them yourself. When the count reaches zero, deinit runs and the memory is returned — immediately, in the same line of execution. That determinism is a real advantage. There are no collection pauses, a released image frees its memory the moment the last screen lets go of it, and a file closed in deinit is closed at a predictable point. The price is the one the table is about: counting cannot see a cycle. Two objects that hold each other keep each other’s count at one forever.
The second half of the model is values. A struct, an enum, a tuple — and String, Array, Dictionary and Set, which are structs in Swift — are copied when they are assigned or passed, so two variables never share one value and there is nothing to count. The standard collections make this cheap with copy-on-write: two copies share one buffer until one of them is changed, and only then is the buffer duplicated. This is why idiomatic Swift starts with a struct and reaches for a class only when identity matters — one shared object that several screens observe, or a resource with a lifetime of its own, such as a connection or a player. Rows 1–3 of the table are easy because most of a Swift program is values.
| Kind of reference | Owns the object? | When the object goes away | Use it for |
|---|---|---|---|
| strong (the default) | Yes | It cannot go away while this reference exists | Almost everything |
| weak | No | The reference becomes nil, so it is always an optional var | Delegates, back-references, closures stored on self — rows 6–11 |
| unowned | No | The reference stays non-optional; using it afterwards stops the app with a runtime trap | A reference that by construction cannot outlive its target |
| unowned(unsafe) | No | Nothing is checked; reading it afterwards is undefined behaviour | Measured hot paths, almost never in app code |
Finding a cycle takes seconds once you look. Put a print or a breakpoint in deinit of the screens you care about: if it does not fire when you navigate away, something still holds the screen. Xcode’s Memory Graph Debugger then draws the objects that hold it, arrows and all, and marks the leaks it can prove. Instruments’ Allocations template answers the volume question: open and close the same screen ten times, and the number of live instances of its view controller should return to where it started. A count that climbs by one per visit is rows 6–16 in a single number.
Leaks matter more on iOS than their size suggests, because the system does not page an app’s memory out to disk. When memory runs short it terminates apps — those in the background first — and an app in the foreground that grows past its own limit is terminated too. This is called a jetsam event. To the user it looks like a crash; to the developer it does not arrive as an ordinary crash report, and shows up instead in the memory terminations Xcode’s Organizer and MetricKit count. Images are the usual cause, for the reason the React Native page gives: decoded, an image costs width × height × 4 bytes, so a 12-megapixel photo is 48 MB however small the JPEG was.
SwiftUI or UIKit — and who owns the state
There are two UIUser Interface — what the user seesEverything the user sees and operates: screens, buttons, fields, states. UI is how the interaction looks; whether the interaction makes sense in the first place is a UX question, and the two get confused constantly.All terms frameworks on the platform, and a working iOS developer reads both. UIKit, there since the first iPhone SDKSoftware Development Kit — ready-made tools for a platformA packaged set of libraries, tools and examples for working with someone else’s platform. The difference from an API is that an API only states the rules, while an SDK hands you code that already knows how to speak them.All terms in 2008, is imperative: you create views, hold references to them and change them when events arrive. SwiftUI, introduced with iOS 13 in 2019, is declarative: you describe what the screen looks like for a given state, and the framework works out what to change — the same model as React, arrived at independently. Most new screens are written in SwiftUI. Most existing apps are UIKit with SwiftUI growing inside them, and the two interoperate in both directions: UIHostingController puts SwiftUI inside UIKit, UIViewRepresentable puts a UIKit view inside SwiftUI.
One fact explains almost every SwiftUI surprise: a SwiftUI view is a struct. It is a description, cheap to make and thrown away after use, and SwiftUI creates new values of it whenever a parent’s body runs again — dozens of times in a busy screen. So state cannot live in the struct. Property wrappers such as @State tell SwiftUI to keep the storage outside the view, attached to the view’s identity — its place in the hierarchy — and to hand it back to every new value of the struct. When identity changes, the state goes with it: a view moved between the branches of an if, or given a new .id, starts again from its initial value. That is the same rule as keys in React, and the same class of bug.
| Wrapper | Owns the data? | Since | Use it for |
|---|---|---|---|
@State | Yes — kept by SwiftUI for as long as the view’s identity lasts | iOS 13 | A value local to the view; since iOS 17 also an @Observable model the view creates |
@Binding | No — reads and writes a parent’s state | iOS 13 | A child that edits a value it does not own |
@Observable class | The class owns its data; a view re-renders only for properties its body read | iOS 17 | Models shared between screens |
@Bindable | No | iOS 17 | Bindings into an @Observable model passed in from outside |
@Environment | No — a value placed higher up the hierarchy | iOS 13 | Dependencies and settings many views read |
@StateObject | Yes — created once per identity | iOS 14 | An ObservableObject the view owns, in code before Observation |
@ObservedObject | No — it only watches an object someone else keeps | iOS 13 | An ObservableObject passed in; never one created right here |
What your minimum iOS version gives you
SwiftUI ships inside the operating system, not inside your app, so the oldest iOS you support decides which SwiftUI you have. A feature added in iOS 17 is simply not there on a phone running iOS 16, and code that uses it needs an if #available branch with a fallback. That makes the deployment target a product decision with a price on both sides: too low, and the team writes fallbacks for features the framework already has; too high, and a share of users cannot install the next update. Adoption of new iOS versions is fast, so most teams support the current version and one or two before it.
| Minimum iOS | Year | What SwiftUI gained |
|---|---|---|
| iOS 13 | 2019 | SwiftUI itself: views, @State, @Binding, @ObservedObject |
| iOS 14 | 2020 | @StateObject, the App protocol, lazy stacks and grids |
| iOS 15 | 2021 | .task — work tied to a view’s lifetime — AsyncImage, .refreshable |
| iOS 16 | 2022 | NavigationStack, Swift Charts, the Layout protocol |
| iOS 17 | 2023 | Observation (@Observable, @Bindable), SwiftData |
| iOS 18 | 2024 | Custom containers, zoom transitions, mesh gradients, the Tab type |
| iOS 26 | 2025 | Liquid Glass, a SwiftUI WebView, rich text in TextEditor |
| iOS 27 | 2026 | Drag-to-reorder in any container, swipe actions outside List, a new document API |
SwiftUI
- Far less code for the same screen, with live previews while you type.
- One framework for iPhone, iPad, Mac, Watch, TV and Vision Pro.
- State has one owner and the screen follows it — no view to keep in sync by hand.
- Your minimum iOS version decides which features exist; edge cases still drop into UIKit.
UIKit
- Eighteen years of answers, libraries and behaviour nobody has to guess at.
- Complete control over layout, transitions, text input and every edge case.
- What most existing apps are written in, so you will read it regardless.
- More code, more state kept in sync by hand, and the delegate and target patterns behind rows 6 and 12.
One more difference between the two showed up in 2025. Both are drawn by the operating system, so when iOS 26 redesigned its controls in Liquid Glass, every SwiftUI and UIKit app rebuilt with the iOS 26 SDK took on the new look — tab bars, navigation bars, switches, alerts — without a line of code. Apple let apps opt out for one year with the UIDesignRequiresCompatibility key, and the key is ignored once an app is built with the iOS 27 SDK. The Flutter page draws what that redesign did to SwiftUI, React Native and Flutter apps side by side; for a native app the work is the custom-drawn views, which change only when you change them.
Swift concurrency: who may touch this state
One rule on this platform never changes: the user interface is touched only from the main thread. The main thread also has a supervisor. A watchdog terminates an app that does not draw its first frame in time or stops answering, and the crash report carries the code 0x8badf00d — “ate bad food”. Apple’s own documentation shows the classic cause: Data(contentsOf:) with an https URL looks like reading a file and quietly makes a synchronous network request on whatever thread called it. On a fast office network it takes milliseconds. On a train it takes long enough for the watchdog.
Swift’s answer, added in Swift 5.5 in 2021, has three parts. async and await let a function wait for a network response or a file without blocking its thread: at each await the function steps aside and the thread does other work. An actor is a type that protects its own state by letting one task in at a time, so two tasks cannot change the same dictionary at once. @MainActor is the actor that stands for the main thread, so marking a view model with it lets the compiler, not code review, check that its methods run there. The third part is Sendable: a type that may safely cross from one actor to another, either because it is a value or because it guards its own state.
Swift 6, in September 2024, made the checks errors rather than warnings in its new language mode: code that could let two threads touch the same mutable state without coordination stops compiling. A data race became a compile error, the same move Rust made with ownership. The first migrations were hard, because most app code had never said which actor it belonged to, and the compiler flagged it everywhere. Swift 6.2, in September 2025, changed the defaults instead of the rules. A module can now make everything @MainActor unless marked otherwise; an async function that is not tied to an actor runs on its caller’s actor instead of jumping to a background thread; and @concurrent marks the functions that should leave. Xcode 26 turned on both settings for new app projects. The modern starting point is therefore single-threaded: code runs on the main actor, and work leaves it on purpose.
| Version | Released | What changed for an app developer |
|---|---|---|
| Swift 5.0 | Mar 2019 | A stable binary interface: the Swift runtime ships in iOS 12.2 and later, so apps stop bundling it |
| Swift 5.5 | Sep 2021 | async/await, actors, structured concurrency, Sendable |
| Swift 5.9 | Sep 2023 | Macros; the Observation framework behind @Observable |
| Swift 6.0 | Sep 2024 | The Swift 6 language mode: data races are compile errors; typed throws |
| Swift 6.2 | Sep 2025 | Main actor by default (opt-in, on in new Xcode 26 projects), @concurrent; InlineArray, Span |
| Swift 6.3 | Mar 2026 | The Swift SDK for Android released; @c for C interop; module selectors (Module::name) |
| Swift 6.4 | Sep 2026 | await inside defer; task cancellation shields; Swift Build as the package manager’s default; ships with Xcode 27 |
Shipping: review, TestFlight and a seven-day rollout
The part that surprises teams arriving from the web is that shipping is not a deploy. Every binary goes through App Review before anyone outside the team can install it. Apple says that on average 90% of submissions are reviewed in less than 24 hours, and that over 40% of the problems that stop a submission fall under guideline 2.1, App Completeness — crashes, placeholder content, a demo account the reviewer could not log in with. For a critical bug fix there is an expedited review, which Apple grants case by case. And since June 2020, a bug fix for an app already on the store is not held back over a guideline violation unless the issue is legal; the cases section says how that rule came about.
There is no way around the binary. Swift is compiled ahead of time to machine code, and the Developer Program License Agreement allows downloaded code only if it is interpreted and does not change the app’s primary purpose — which is what lets React Native ship over-the-airupdating installed software remotelyAn update delivered over the network to software already installed on a device, without the user reinstalling it — a JavaScript bundle for a React Native app, firmware for a phone or a drone. On iOS and Google Play only interpreted code may arrive this way; native code needs a new build and a store review.Full article →All terms updates, and the React Native page quotes the clause. What a native app can change without a release is what it was built to read: server-driven content, remote configuration, a feature flaga switch around new codeA switch that decides at run time whether a piece of code is active, so it can ship to production turned off and be turned on for a chosen audience later. It separates deploying from releasing, and it costs something: every live flag is a branch in the code that has to work in both states.Full article →All terms that switches on code already in the binary. Anything else waits for the next build, which is why the order of the steps below matters.
TestFlight is the step before the store. Up to 100 internal testers with access to the team’s App Store Connect account get a build as soon as it has finished processing. Up to 10,000 external testers can join by invitation or a public link; the first build for them goes through Beta App Review. Each build stays installable for 90 days. Then comes the release itself, and the most useful switch in App Store Connect: a phased release. The update reaches 1% of users on day one, then 2%, 5%, 10%, 20%, 50% and everyone on day seven. You can pause it for up to 30 days in total, or release to everyone at once.
Apple’s calendar — the requirements in force around this page’s date
| Since | What it requires | What it means in the code |
|---|---|---|
| 30 Jun 2022 | An app that lets people create an account lets them delete it inside the app (guideline 5.1.1(v)) | A real deletion path — deactivation is not enough — and Sign in with Apple tokens revoked |
| 1 May 2024 | Approved reasons for “required reason” APIs, including those called by third-party SDKs | A privacy manifest declaring why the app reads user defaults, file timestamps, boot time, free disk space or the active keyboards |
| 31 Jan 2026 | Answers to the new age-rating questions for every app | Without them, updates stop at submission |
| 28 Apr 2026 | Uploads built with Xcode 26 and the iOS 26 SDK | Liquid Glass on every system control; the one-year opt-out key still works |
| 9 Sep 2026 | Uploads target iOS 13 or later | A deployment target below iOS 13 is rejected at upload |
| Building with Xcode 27 (released 14 Sep 2026) | The scene-based (UIScene) lifecycle, or the app does not launch; UIDesignRequiresCompatibility ignored | An app delegate that owns the window has to move to a scene delegate before the iOS 27 SDK becomes mandatory — Apple has raised the minimum SDK every April |
| 2 Dec 2026 (planned) | CocoaPods trunk becomes read-only | Existing builds keep working, but no new versions of any pod arrive; move dependencies to Swift Package Manager |
Which iOS codebase are you looking at
| What you see in the code | What it tells you |
|---|---|
An AppDelegate with a window property and no SceneDelegate | The pre-iOS 13 lifecycle; built with the iOS 27 SDK, the app does not launch |
ObservableObject, @Published and @StateObject everywhere | Written before Observation (iOS 17); works, but every change re-renders every view that observes the object |
NavigationView | Deprecated since iOS 16; NavigationStack replaces it |
Completion handlers and DispatchQueue.main.async in every network call | Concurrency from before 2021, which the compiler’s data-race checks cannot see into |
SWIFT_VERSION = 5 with minimal concurrency checking | Nobody has asked the compiler about data races yet; turn checking up one module at a time |
A Podfile | CocoaPods, whose central repository stops accepting new versions on 2 Dec 2026 |
UIDesignRequiresCompatibility set to YES in Info.plist | The team postponed Liquid Glass; with the iOS 27 SDK the key is ignored |
Timer.scheduledTimer(… target: self …) with no invalidate() nearby | Row 12 of the table, waiting to be found |
Five cases, and what each one was missing
A native iOS team inherits two things it does not control: the code of every SDK it ships, and the rules of the company that runs the store. All five cases are about one or the other, and each is documented by the people involved — a GitHub issue, a company statement, Apple’s own announcements.
| Case | What happened | What was missing |
|---|---|---|
| Facebook SDK, 6 May and 10 Jul 2020 | A change on Facebook’s servers crashed Spotify, Pinterest, TikTok, Venmo and others at launch, twice | A way to switch a third-party SDK off, and parsing that does not trust the server |
| HEY, June 2020 | A bug-fix update rejected because the app sold its subscription only on the web; approved on 22 June after adding a free 14-day address | The business model checked against guideline 3.1 before the code was written |
| The iOS 14 paste banner, June 2020 | The first beta showed a banner whenever an app read the clipboard; TikTok read it every few keystrokes, LinkedIn on every one | An inventory of what the app and its SDKs read — required since May 2024 as a privacy manifest |
| App Tracking Transparency, Apr 2021 | iOS 14.5 required a prompt before tracking across other companies’ apps; Meta estimated the cost at about $10 billion of 2022 revenue | A product that did not depend on a default the operating system could change |
| Account deletion, 30 Jun 2022 | Apps with sign-up had to offer deletion inside the app; the deadline had already been extended once | A deletion path designed with sign-up, not after review found it missing |
The first case shows what an SDK at launch can do. On 6 May 2020, from 14:44 Pacific time, apps that embedded Facebook’s iOS SDK began to crash the moment they opened — Spotify, Pinterest, TikTok, Venmo, Tinder and more, including for users who never signed in with Facebook. The issue filed on GitHub that afternoon pointed at one line: the SDK downloaded a configuration from Facebook’s servers at start-up and read a value in it as a dictionary, and the server had started sending something else. Facebook fixed it on the server within hours. On 10 July 2020 it happened again, through the same component. The affected apps had done nothing wrong in their own code. What they lacked was distance: an SDK initialised on the launch path, before the first screen, with no switch to turn it off remotely, and no tolerance for a server that answers in an unexpected shape.
The third case is the operating system making visible what code had always done. In June 2020 the first iOS 14 beta started showing a small banner whenever an app read the clipboard. Within days users posted recordings: TikTok read it every few keystrokes, LinkedIn on every keystroke. TikTok said it was an anti-spam feature and removed it; LinkedIn called it a bug. The banner did not care whose code read the clipboard — the app’s own or an SDK inside it — and that is the point: a team answers for everything its binary does. Apple turned that into a requirement in May 2024: an upload must declare an approved reason for each “required reason” API it calls, including those called by third-party SDKs. The fourth case is the same pattern at larger scale. With iOS 14.5, on 26 April 2021, an app had to ask before tracking a person across other companies’ apps, and the system shows that prompt once. In February 2022 Meta told investors the change would cost it on the order of $10 billion that year — an estimate, its chief financial officer said, and the only number of its size anyone published. A default the platform owns can be changed by the platform.
Where it degrades
Native iOS is generous where a team is disciplined and quiet where it is not. The compiler catches more each year — data races since Swift 6 — but it still cannot tell you that a screen was never freed, that an SDK reads the clipboard, or that the next SDK requirement is six months away. Almost every failure is one of these:
- Stored closures and delegates that capture their owner strongly, leaking silently and never crashing (rows 6–9).
- Timers, display links, sessions and web-view handlers nobody invalidates (rows 12–15).
- A task that loops forever and keeps its screen with it (row 11).
unownedwhereweakwas meant, which turns a leak into a crash on a slow network.- A model created inside
@ObservedObject, which resets every time the parent updates. - Synchronous work on the main thread — a file, a decode, a hidden network call — until the watchdog ends it.
- A continuation that is not resumed on every path, leaving a screen loading forever.
- Third-party SDKs started at launch with no way to switch them off and no list of what they read.
- Permission prompts at launch instead of at the moment a feature needs them — the system asks once.
- Apple’s requirements — deletion, privacy manifests, the scene lifecycle, the minimum SDK — discovered on the day the release was due.
The honest limit is the platform itself. A native iOS app is the best version of an app on an iPhone — the newest APIs on day one, the platform’s own controls and their redesigns for free, deterministic memory, a compiler that rules out data races. It is also one platform. A product that needs Android too pays for a second native team, or for a cross-platform layer, or — as Shopify concluded in September 2026, a story the React Native page tells — for coding agents that translate between the two; none of those is free. And every release still passes through one company’s review and one company’s calendar. A team that plans for both treats them as part of the schedule rather than as weather.
The practical check takes ten minutes. Read the deployment target and the Xcode version, and find them in the calendar table. Search the code for var delegate: without weak, Timer.scheduledTimer(, addObserver(forName:, .sink { without a capture list, URLSession(configuration: with a delegate and add(self, name:. Open and close the three busiest screens ten times each with the Memory Graph Debugger open. Check that Info.plist declares a scene manifest. Look at the Swift language mode and the concurrency-checking level of each target. And confirm that the next release is set to use a phased release.
When to use it
Use it when
- Products where the iPhone experience is the product — performance, polish and the platform’s conventions.
- Anything built on a capability Apple ships first — widgets, Live Activities, on-device models, new hardware.
- Apps where deterministic memory, no collection pauses and compile-time data-race checks genuinely matter.
- Teams that can support one platform properly rather than two approximately.
Avoid it when
- Products that need both platforms with one team and one budget — that is what the cross-platform tools are for.
- Anything that must change its native code the same day; every binary goes through review, and there is no rollback.
- Business models that conflict with the store’s payment rules — resolve that before writing code.
- A team with no Mac hardware and no capacity to follow Apple’s yearly SDK calendar; there is no way around Xcode.
Sources and method
What this page stands on
- 18 sources
- 2 documented failures
- Checked October 13, 2026
Practices and where the terms come from
who holds whom: ARC, the APIs that retain, and the lifecycle- GuideThe Swift Programming Language — Automatic Reference Counting (opens in a new tab)swift.org
- DocumentationTimer (opens in a new tab)Apple Developer Documentation
- DocumentationURLSession (opens in a new tab)Apple Developer Documentation
- DocumentationState (opens in a new tab)Apple Developer Documentation
- DocumentationAddressing watchdog terminations (opens in a new tab)Apple Developer Documentation
- DocumentationTN3187: Migrating to the UIKit scene-based life cycle (opens in a new tab)Apple Developer Documentation
- DocumentationWebKit — WKUserContentController.mm (opens in a new tab)GitHub · WebKit
- ArticleSwift 6.4 Released (opens in a new tab)Swift.org · Sep 15, 2026
- DocumentationApp Review (opens in a new tab)Apple Developer
- DocumentationUpcoming Requirements (opens in a new tab)Apple Developer
- ArticleCocoaPods Trunk Read-only Plan (opens in a new tab)CocoaPods Blog · May 2025
The failures this page learns from
the Facebook SDK crash and HEY, in “Five cases”- PostmortemSuddenly FBSDKRestrictiveDataFilterManager.m - Line 71 started to crash — facebook-ios-sdk #1373 (opens in a new tab)GitHub · May 6, 2020
- PostmortemApp suddenly crashing on startup in production due to FBSDKRestrictiveDataFilterManager — #1427 (opens in a new tab)GitHub · Jul 10, 2020
- ArticleSeveral major iOS apps crashing at launch due to Facebook SDK issues (opens in a new tab)TechCrunch · May 6, 2020
- ArticleApple approves Hey email app update as company adds time-limited free accounts (opens in a new tab)9to5Mac · Jun 22, 2020
Privacy rules that changed apps
the paste banner, App Tracking Transparency and account deletion- ArticleTikTok to stop reading user clipboards after being exposed by iOS 14 privacy feature (opens in a new tab)9to5Mac · Jun 25, 2020
- ArticleFacebook says Apple iOS privacy change will result in $10 billion revenue hit this year (opens in a new tab)CNBC · Feb 2, 2022
- DocumentationAccount deletion requirement starts June 30 (opens in a new tab)Apple Developer News · May 24, 2022
Researched with Claude. Finding and cross-checking the primary sources was done with Claude (Anthropic). Selection, writing and fact-checking: the Anatomy of IT Product editors.
Found this useful?
Share it with someone who is working on the same problem.