Awesome iOS Developer

July 19, 2026 · View on GitHub

Awesome

A practical, opinionated field guide for building high-quality iOS apps with Swift.

This repository is a map, not a checklist. Start with the fundamentals, build a small app end to end, and return to the deeper topics when a real problem gives them context.

The guide favors first-party frameworks, official documentation, measurable engineering practices, and dependencies that solve a demonstrated need. It also keeps UIKit, Objective-C interoperability, Core Data, Combine, and older package managers visible because production iOS work often includes mature codebases.

🔎 Contents

🚀 Start Here

A sensible learning order

StageLearnBuild
1. LanguageSwift syntax, value and reference semantics, protocols, generics, optionals, errors, and collectionsA command-line or playground model
2. ToolsXcode, Simulator, Git, breakpoints, schemes, build settings, and Swift Package ManagerA small app that builds from a clean checkout
3. InterfaceSwiftUI, UIKit basics, layout, navigation, state, and the Human Interface GuidelinesA multi-screen app with loading, empty, error, and content states
4. DataCodable, URLSession, persistence, caching, and dependency injectionAn app that works with both remote and local data
5. ReliabilitySwift concurrency, unit tests, UI tests, accessibility, localization, and observabilityA tested feature that handles cancellation and failure
6. DeliveryCode signing, CI, TestFlight, privacy declarations, and App Store reviewA beta build delivered to testers

The default stack

Use this as a starting point, not as a rule that every app must follow.

NeedStart withReach for something else when
UISwiftUIUIKit offers required control, platform coverage, or integration
Imperative UI and mature appsUIKitSwiftUI clearly reduces complexity for the feature
ConcurrencySwift async/await, tasks, actors, and SendableA lower-level primitive is justified by measurement or interoperability
NetworkingURLSession, Codable, and HTTP cachingThe app has a proven need for a networking abstraction
PreferencesUserDefaults or SwiftUI app storageThe data is sensitive, relational, large, or user-created
SecretsKeychain ServicesA server should own the secret instead of the app
Structured persistenceSwiftDataCore Data better fits deployment targets, migrations, or an existing store
Unit testsSwift TestingExisting XCTest coverage or an XCTest-only capability makes migration unnecessary
UI and performance testsXCTest and XCUITestA focused third-party tool provides measurable value
DependenciesSwift Package ManagerA legacy dependency is only distributed another way
LoggingLogger and unified loggingA backend observability product is required

What “production ready” means

  • The app handles loading, empty, offline, error, cancellation, and retry states deliberately.
  • The main thread stays responsive and shared mutable state has an explicit isolation strategy.
  • Tests protect important behavior, while analytics, logs, and crash reports make failures diagnosable.
  • Accessibility, localization, privacy, and security are part of feature design rather than release-week cleanup.
  • CI can reproduce the build from a clean checkout.
  • A human can explain every dependency, permission, entitlement, and piece of collected data.

🧑‍💻 Swift and Xcode

Swift

Focus on these concepts before collecting framework recipes:

  • Value semantics, copy-on-write behavior, identity, and ownership.
  • Optionals and error propagation without force-unwrapping normal failure states.
  • Protocols and generics for real substitution, not abstraction for its own sake.
  • Access control and module boundaries.
  • Closures, capture semantics, and avoiding accidental retain cycles.
  • async/await, actor isolation, Sendable, cancellation, and task lifetime.
  • Memory ownership with strong, weak, and unowned references.

Style and static analysis

Consistency matters more than allegiance to one style guide. Automate rules that are objective and leave design judgment to review.

Do not make a build depend on a developer’s globally installed formatter or linter without documenting and pinning the expected version. Swift Package plugins, a repository tool installer, or CI-managed tooling make clean checkouts more reproducible.

Xcode

Learn the tool instead of treating it as a Run button.

  • Targets describe products that Xcode builds.
  • Schemes describe actions such as Run, Test, Profile, Analyze, and Archive.
  • Build configurations describe groups of settings such as Debug and Release.
  • .xcconfig files keep build settings reviewable and reduce configuration drift.
  • Test plans organize test configurations, languages, locales, sanitizers, and execution policies.
  • The Organizer surfaces archives, crashes, hangs, energy use, and distributed performance data.

Useful official references:

Git and repository hygiene

  • Commit one coherent change at a time.
  • Keep generated files, local user data, build products, and credentials out of source control.
  • Review Package.resolved changes as dependency changes, not noise.
  • Prefer small pull requests with a clear purpose, validation evidence, and rollback path.
  • Protect the default branch with required reviews and required CI checks.

📱 Application and UI Fundamentals

Application lifecycle

A modern app may use SwiftUI lifecycle APIs, UIKit lifecycle APIs, or both.

  • SwiftUI apps define an entry point with the App protocol and organize UI through scenes.
  • UIKit apps use UIApplicationDelegate, UISceneDelegate, windows, and view controllers.
  • Background execution is constrained by the system, so save durable state when it changes instead of relying on termination callbacks.
  • Scene phase changes are signals to pause, resume, refresh, or persist work, not guarantees about future lifecycle events.

SwiftUI

SwiftUI is Apple’s declarative UI framework across Apple platforms. Its core skill is not memorizing modifiers; it is understanding identity, data flow, layout proposals, navigation state, and update behavior.

Learn:

  • View identity and the difference between view values and stored model state.
  • @State, bindings, environment values, and the Observation framework.
  • NavigationStack, sheets, popovers, alerts, and state-driven presentation.
  • Lists, grids, custom layouts, animation, gestures, focus, and keyboard behavior.
  • Previews as a fast feedback tool rather than a substitute for tests.
  • UIKit interoperability through representable types and hosting controllers.

Recommended references:

UIKit

UIKit remains important for mature applications, specialized controls, established navigation stacks, and APIs that expose UIKit-first integration points.

Learn:

  • View-controller containment and presentation.
  • Auto Layout, intrinsic content size, content hugging, and compression resistance.
  • Collection views and diffable data sources.
  • Trait collections, adaptive layout, Dynamic Type, and appearance changes.
  • Reuse, prefetching, cell configuration, and scrolling performance.
  • Responder-chain, event, focus, and keyboard behavior.

Recommended references:

Design

The Human Interface Guidelines should be the first design reference. Respect platform behavior before creating custom interaction patterns.

Design and asset tools:

Check every important screen with:

  • Small and large devices.
  • Portrait and landscape when supported.
  • Light and dark appearances.
  • Larger accessibility text sizes.
  • Right-to-left layout.
  • Long translated strings.
  • Reduced motion and increased contrast.
  • Offline, empty, loading, and failure states.

🧭 State, Architecture, and Navigation

Architecture should make change safer. It should not exist to maximize the number of folders, protocols, or diagrams.

Start with boundaries

For a small feature, three responsibilities are often enough:

  1. Presentation renders state and forwards user intent.
  2. Domain logic decides what the feature means and how state changes.
  3. Data access talks to remote services, persistence, and system APIs.

Keep dependencies pointing inward toward policy and domain behavior. Create protocols at boundaries where substitution, testing, or multiple implementations are real requirements.

Dependency injection

Initializer injection should be the default because it makes dependencies explicit and allows immutable storage. Property and method injection are useful when lifecycle or framework integration requires them. A composition root should assemble the concrete dependency graph near the application entry point.

Avoid using a service locator or global singleton as invisible dependency injection. Shared stateless services can be reasonable, but shared mutable state needs explicit ownership and isolation.

Common patterns

PatternUseful whenWatch for
MVCThe feature is small and framework conventions already provide the separationMassive view controllers and business logic tied to UIKit
MVVMPresentation state and transformations deserve a testable modelView models that become an entire application layer
Coordinator or RouterNavigation policy is complex or reusedNavigation abstractions that mirror UIKit without simplifying it
Reducer or unidirectional flowState transitions, effects, and replayable tests are valuableBoilerplate for simple screens
RepositoryMultiple data sources need one domain-facing interfaceGeneric CRUD repositories that erase useful domain meaning
AdapterAn external or legacy API does not match the interface the feature needsWrapping every dependency without a concrete mismatch
FactoryConstruction varies and callers should not know concrete typesA factory with one permanent branch
ObserverOne-to-many change propagation is inherent to the problemUnbounded subscriptions, unclear ownership, and hidden control flow

Architecture references:

No architecture is automatically “clean.” Judge it by dependency direction, testability, clarity, build performance, and how safely the team can change behavior.

  • Model navigation as state when deep links, restoration, or tests need deterministic behavior.
  • Keep URL parsing and route authorization separate from view construction.
  • Validate external deep links and universal links as untrusted input.
  • Decide which feature owns dismissal, cancellation, and returned results.
  • Test cold-start and already-running deep-link flows.

⚡ Concurrency

Swift concurrency is the default model for new asynchronous Swift code.

Learn:

  • async functions and await suspension points.
  • Structured child tasks and task groups.
  • Actor isolation and @MainActor.
  • Sendable and safe transfers between isolation domains.
  • Cancellation as a normal control-flow event.
  • AsyncSequence for streams of values.
  • Continuations for carefully bridging callback APIs.

Rules of thumb:

  • Keep UI state on the main actor.
  • Do not block the main actor with synchronous I/O, waiting, or expensive computation.
  • Prefer structured tasks whose lifetime follows the operation that created them.
  • Check cancellation before expensive or user-irrelevant work.
  • Avoid Task.detached unless the work truly should not inherit actor, priority, task-local values, or cancellation.
  • Treat @unchecked Sendable as a reviewed safety assertion, not a compiler escape hatch.
  • Use actors to protect shared mutable state when actor isolation fits the access pattern.
  • Measure before replacing clear actor-based code with locks or custom executors.

Grand Central Dispatch, locks, operation queues, and semaphores remain relevant for legacy code, framework interoperability, and specialized synchronization. Do not mix concurrency models casually or assume a serial queue automatically makes an entire object safe.

References:

🌐 Networking

Start with URLSession, Codable, HTTPURLResponse, and Swift concurrency. Add an abstraction when the app needs consistent authentication, retries, caching, metrics, decoding, or endpoint construction.

enum APIError: Error {
    case invalidResponse
}

let (data, response) = try await URLSession.shared.data(for: request)

guard let httpResponse = response as? HTTPURLResponse,
      200..<300 ~= httpResponse.statusCode else {
    throw APIError.invalidResponse
}

let model = try JSONDecoder().decode(Model.self, from: data)

Production networking needs more than a successful JSON decode:

  • Define request and response contracts.
  • Map transport, HTTP, decoding, authentication, cancellation, and domain errors separately.
  • Set timeouts intentionally.
  • Respect HTTP caching and conditional requests.
  • Retry only operations that are safe to repeat, with limits, delay, and jitter.
  • Propagate cancellation when a screen or operation no longer needs the response.
  • Redact authorization headers, tokens, personal data, and request bodies from logs.
  • Monitor latency, status codes, payload size, and failure rate without collecting unnecessary user data.
  • Test malformed payloads, missing fields, server errors, offline behavior, slow responses, and cancellation.

Never ship a privileged API secret in an iOS application. Anything in the app bundle or process should be treated as recoverable by an attacker. Keep privileged credentials and authorization decisions on a server you control.

Useful references:

💾 Persistence

Choose storage from data semantics, not familiarity.

DataAppropriate starting point
Small preferences and feature flagsUserDefaults
Credentials, tokens, and small secretsKeychain Services
User-created documentsDocuments directory or a document-based API
Re-creatable downloads and derived filesCaches directory
Structured object graph for a modern deployment targetSwiftData
Mature object graph, advanced migrations, or existing storeCore Data
Cross-device Apple ecosystem syncCloudKit, directly or through a supported persistence integration

UserDefaults

UserDefaults is for preferences and small property-list values. It is not a database, secure storage, or a good home for large encoded object graphs. Use UserDefaults.standard unless an app group or a dedicated suite is required.

File system

Use FileManager URLs instead of hard-coded paths. Choose Documents, Application Support, Caches, or temporary storage according to ownership, backup behavior, and whether the data can be recreated. Use atomic writes where partial files would be harmful.

SwiftData

SwiftData integrates a model layer with Swift and SwiftUI. Evaluate deployment targets, migration needs, CloudKit behavior, query complexity, and testability before choosing it.

Core Data

Core Data is an object graph and persistence framework, not simply a SQLite wrapper. The backing store is an implementation choice, and managed objects belong to their managed object context.

Important topics:

  • Persistent containers, contexts, and save propagation.
  • Queue confinement and concurrency.
  • Fetch requests, predicates, sorting, batching, and faulting.
  • Unique constraints, relationships, inverse relationships, and delete rules.
  • Lightweight and custom migration.
  • Persistent history and remote changes when multiple writers exist.
  • In-memory stores for focused tests.

Avoid fetching a global context through UIApplication.shared.delegate. Inject a persistence boundary or context appropriate to the feature and execution domain.

🧩 System Capabilities

Add a capability because the product needs it, then study its lifecycle, permissions, background behavior, and failure modes.

CapabilityFramework or starting point
Local and remote notificationsUserNotifications
Push deliveryApple Push Notification service
LocationCore Location
Bluetooth Low EnergyCore Bluetooth
Photos and limited-library accessPhotoKit
Camera and media captureAVFoundation
Biometrics and device-owner authenticationLocalAuthentication
Background workBackgroundTasks
Widgets and controlsWidgetKit
Live ActivitiesActivityKit
Siri, Shortcuts, Spotlight, and system actionsApp Intents
Health dataHealthKit
MapsMapKit
Purchases and subscriptionsStoreKit

Request permission in context, explain the benefit before the system prompt, and make denial a supported product state. Include accurate usage-description strings for protected resources. Do not request capabilities “for later.”

Notifications

  • Ask for authorization at a moment when the user understands the value.
  • A local repeating notification must use a valid interval and system-supported trigger.
  • Remote notification delivery is not guaranteed and should not be the only source of durable state.
  • Keep device tokens associated with the correct environment, app, user, and installation.
  • Treat notification payloads and deep-link values as untrusted input.

Biometrics

Use LAContext to evaluate a policy, and handle unavailable, unenrolled, locked-out, canceled, and fallback states. Biometrics authenticate device ownership or presence; they do not replace server-side authorization. Store protected secrets in the Keychain with an access-control policy appropriate to the product.

📦 Dependencies and Modularization

Swift Package Manager first

Swift Package Manager is the default dependency manager for new Swift code. Use CocoaPods or Carthage when maintaining a project or integrating a dependency that still requires them.

Before adding a dependency, check:

  • Whether an Apple framework or a small amount of clear code already solves the problem.
  • Maintenance activity and response to security issues.
  • License compatibility.
  • Supported platforms and toolchains.
  • Transitive dependencies.
  • Binary size and build-time cost.
  • Concurrency annotations and strict-concurrency readiness.
  • Privacy manifest and required-reason API declarations.
  • Migration and removal cost.

Review dependency updates like code changes. Pin according to the project’s risk tolerance, keep the resolved graph in source control for applications, and automate update visibility.

Useful packages and tools

These are options to evaluate, not a default shopping list.

ProjectPurpose
SwiftLintEnforce selected Swift style and correctness rules
swift-formatFormat Swift source
SwiftGenGenerate type-safe resource access
PeripheryDetect unused Swift code
AlamofireNetworking features and request abstraction
KingfisherImage downloading and caching
SDWebImageImage loading and caching across Apple UI frameworks
The Composable ArchitectureReducer-based application architecture
swift-dependenciesDependency management designed for testability
swift-snapshot-testingSnapshot tests for values and UI
Quick and NimbleBehavior-style test organization and matchers
Swift CollectionsAdditional data structures
Swift AlgorithmsSequence and collection algorithms

Modularization

Modules should express ownership and dependency boundaries. They are not automatically an improvement.

Modularize when it provides one or more of these benefits:

  • Independent ownership or release.
  • Enforced access control.
  • Reuse across products.
  • Smaller test and build scopes.
  • Isolation of volatile infrastructure.
  • A stable feature or domain boundary.

Track build time before and after modularization. An excessive module graph can increase configuration, dependency, and linking costs.

Useful tools:

  • Tuist for generated projects, workspaces, caching, and project automation.
  • XcodeGen for generating Xcode projects from specifications.
  • XCFrameworks for distributing multi-platform binary frameworks.
  • DocC for API and conceptual documentation.

🧪 Testing

Tests should protect behavior that matters and make refactoring safer. A large test count is not evidence of useful coverage.

Choose the right layer

TestBest forAvoid
UnitPure logic, reducers, transformations, validation, and edge casesRe-testing framework behavior
IntegrationPersistence, networking boundaries, decoding, migrations, and module contractsCalling uncontrolled production services
UICritical user journeys and system integrationReproducing every unit-level branch through the UI
SnapshotStable visual or structural outputTreating every pixel change as a regression
PerformanceLaunch, scrolling, algorithms, persistence, and memory-sensitive behaviorThresholds that are noisy on shared CI hardware

Swift Testing and XCTest

Use Swift Testing for new Swift unit tests when it fits the project. It supports parameterization, traits, tags, concurrency, and flexible suite organization.

Use XCTest for UI tests, performance tests, Objective-C tests, and existing suites. Swift Testing and XCTest can coexist during incremental migration, but do not mix their APIs inside one test.

Test doubles

  • A dummy fills an unused parameter.
  • A stub returns controlled answers.
  • A spy records interactions for later verification.
  • A mock verifies expected interactions.
  • A fake provides a working but simplified implementation, such as an in-memory repository.

Prefer a fake or stub that expresses behavior over a brittle mock of implementation details.

UI testing

  • Use accessibility identifiers only where semantic queries are insufficient.
  • Keep screen interaction behind small robot or page objects when it improves readability.
  • Reset state deterministically.
  • Disable uncontrolled animations or network dependencies through launch configuration.
  • Capture screenshots and logs on failure.
  • Test permissions, deep links, interruptions, and relaunch behavior where they affect critical journeys.

Accessibility testing

Run Accessibility Inspector audits and automate appropriate checks with XCUITest. Automated audits catch common issues but do not replace VoiceOver, Switch Control, keyboard, and real-device testing.

StoreKit testing

Use a StoreKit configuration for local development and deterministic tests. Use the sandbox and TestFlight to validate App Store Connect products and server interactions. Test success, cancellation, pending approval, failed purchase, restore, refund, renewal, expiration, grace period, and interrupted transactions.

References:

🐛 Debugging, Performance, and Observability

Debugging

Learn these Xcode tools:

  • Source, symbolic, exception, and runtime-issue breakpoints.
  • LLDB commands such as po, p, expression, bt, and breakpoint commands.
  • View hierarchy debugger.
  • Memory graph debugger.
  • Address Sanitizer, Thread Sanitizer, and Undefined Behavior Sanitizer.
  • Main Thread Checker and Thread Performance Checker.
  • Network and file activity instruments.
  • Crash and hang reports in Organizer.

Never “fix” a race by adding arbitrary delay. Reproduce it, identify the ownership or isolation violation, and leave a test or diagnostic that would catch the regression.

Performance

Measure on a representative physical device with an optimized build. Simulator results are useful for iteration but do not represent device CPU, GPU, memory pressure, thermal behavior, or power use.

Watch:

  • Launch and first-interaction latency.
  • Hangs, hitches, and main-thread work.
  • Scrolling and animation frame time.
  • Memory growth, leaks, retain cycles, and termination pressure.
  • Disk and network I/O.
  • Battery and thermal impact.
  • Download size, installed size, and on-demand resources.

Use Instruments and Xcode performance tools before guessing.

Logging and metrics

Use unified logging through Logger. Choose subsystem, category, and level deliberately. Mark sensitive interpolated values as private and avoid logging secrets or full payloads.

Use signposts for important intervals that need Instruments correlation. Use MetricKit and Xcode Organizer to understand behavior on distributed builds. Use crash reporting and product analytics only with clear privacy rules, retention, and consent where required.

♿ Accessibility and Localization

Accessibility

Accessibility is a product requirement. Build with semantic system controls first, then add custom accessibility behavior where the UI needs it.

Verify:

  • Useful labels, values, hints, traits, actions, and focus order.
  • Dynamic Type without clipping or hiding essential actions.
  • Sufficient contrast without relying on color alone.
  • VoiceOver reading order and rotor behavior.
  • Reduce Motion, Reduce Transparency, Bold Text, and Increased Contrast.
  • Switch Control, Voice Control, Full Keyboard Access, and external keyboards where relevant.
  • Captions, transcripts, and alternatives for meaningful audio or visual content.

References:

Localization

Localization includes language, pluralization, grammar, layout direction, calendars, dates, times, numbers, names, units, and culturally appropriate assets.

Use String Catalogs for new Xcode projects. Provide translator comments and avoid constructing user-facing sentences from fragments. Use FormatStyle and locale-aware Foundation formatters instead of hand-built date or number strings.

Test:

  • Every supported language and a pseudolanguage.
  • Long strings and large text.
  • Right-to-left layout.
  • Singular, plural, and grammatical variants.
  • Non-Gregorian calendars and 12/24-hour time where product behavior depends on them.
  • Region-specific prices, decimal separators, measurement systems, and names.

References:

🔐 Security and Privacy

Security is risk management, not a checklist of tricks. Start with a threat model: identify assets, trust boundaries, attackers, abuse cases, and the impact of failure.

Baseline

  • Minimize collected data and retention.
  • Keep authorization decisions and privileged credentials on the server.
  • Use TLS and App Transport Security without broad exceptions.
  • Store small secrets in the Keychain with appropriate accessibility and access-control settings.
  • Use CryptoKit or other reviewed platform cryptography instead of designing cryptographic algorithms.
  • Validate every server response, deep link, file, pasteboard value, notification payload, and imported document.
  • Redact secrets and personal data from logs, analytics, screenshots, and crash metadata.
  • Review third-party SDK behavior, privacy manifests, signatures, licenses, and transitive dependencies.
  • Keep development menus, debug endpoints, and verbose logging out of production builds.
  • Handle compromised credentials and server-side revocation.

Transport security and pinning

App Transport Security enforces secure connection requirements by default. Use narrowly scoped exceptions only when a documented compatibility requirement leaves no safer option.

Certificate or public-key pinning adds operational risk. Use it only when the threat model justifies it and the team can support backup pins, certificate rotation, expiration, incident recovery, and remote failure. Do not copy deprecated SecTrustEvaluate examples or assume pinning replaces normal trust evaluation.

Keychain and cryptography

Privacy

Privacy work includes both product behavior and App Store declarations.

  • Maintain accurate App Privacy answers in App Store Connect.
  • Include valid privacy manifests and required-reason API declarations where applicable.
  • Audit included SDKs because their collection and required-reason APIs become part of the app.
  • Ask for protected-resource access only when the feature needs it.
  • Provide account and data deletion flows where policy or law requires them.
  • Make consent specific and avoid dark patterns.

References:

Obfuscation and jailbreak detection can raise the cost of analysis, but neither establishes a trustworthy device. Treat them as optional defense-in-depth controls, not security boundaries.

🔄 CI/CD and Team Workflow

CI should make the repository reproducible and the default branch trustworthy.

A useful pull-request pipeline:

  1. Resolve dependencies from a clean checkout.
  2. Build supported configurations.
  3. Run formatting and lint checks.
  4. Run unit and integration tests.
  5. Run selected UI, accessibility, and performance tests.
  6. Scan for secrets and vulnerable dependencies.
  7. Archive or export a build when distribution behavior matters.
  8. Publish concise logs, test results, and artifacts.

Keep signing material and credentials in the CI provider’s protected secret store. Use short-lived credentials or workload identity when supported. Do not run secret-bearing workflows against untrusted pull-request code.

Tools:

Build performance

Treat build time as a measured developer-experience metric.

  • Inspect Xcode build timing summaries and dependency graphs.
  • Keep run-script phases deterministic and declare their inputs and outputs.
  • Avoid unnecessary code generation and always-run scripts.
  • Measure type-checking and module-boundary changes.
  • Cache only artifacts that are safe and correctly keyed.
  • Use project-generation focus or selective-build features only after measuring the bottleneck.

🚢 Distribution and Monetization

Code signing

Understand:

  • Bundle identifiers, App IDs, certificates, provisioning profiles, entitlements, and capabilities.
  • Development, Ad Hoc, TestFlight, App Store, and enterprise distribution differences.
  • Automatic signing versus intentionally managed signing in CI.
  • Export compliance and privacy requirements.

References:

TestFlight

TestFlight distributes beta builds and collects feedback before release. Test migration, account, notification, background, purchase, and server-compatibility behavior on TestFlight rather than assuming a development build is equivalent.

App Store

Read the App Review Guidelines before implementation decisions become expensive. Validate metadata, screenshots, privacy answers, support URLs, account deletion, review notes, and demo credentials before submission.

StoreKit and subscriptions

Use StoreKit 2 for modern Swift purchase flows. Model entitlement state independently from the paywall UI. Verify transactions, finish processed transactions, listen for updates, restore access, and design for purchases that occur on another device or outside the app.

Testing does not require a physical device for every stage. StoreKit Testing in Xcode supports local purchase scenarios, while sandbox and TestFlight cover App Store-connected behavior.

Useful references:

Test renewal, expiration, cancellation, refund, revocation, billing retry, grace period, upgrade, downgrade, restore, Ask to Buy, and interrupted transactions. Do not unlock durable server-owned value based only on an unverified client boolean.

🧱 Legacy Code and Interoperability

Production iOS development often includes APIs and patterns that are no longer the first choice for a new app. Learn enough to maintain them safely before attempting a migration.

Objective-C

Understand:

  • Header and implementation files.
  • Categories, protocols, delegates, blocks, and nullability.
  • Dynamic dispatch, selectors, KVC, and KVO.
  • ARC ownership and retain-cycle behavior.
  • Bridging headers and generated Swift interfaces.
  • Module maps and framework boundaries.

References:

Do not describe a Swift app as free of Objective-C runtime or C-family foundations merely because the application target contains only .swift files. That fact rarely affects product architecture, so investigate it only when interoperability, runtime behavior, or debugging makes it relevant.

Frameworks and patterns you may inherit

  • UIKit storyboards and nibs.
  • Core Data.
  • Objective-C modules.
  • CocoaPods and Carthage.
  • GCD and OperationQueue.
  • Combine and RxSwift.
  • MVC, MVVM, VIPER, coordinators, and custom routers.
  • Custom networking and persistence layers.

Migration rule: preserve behavior first, add characterization tests, move one boundary at a time, and measure the result. A rewrite is not automatically simpler than the code it replaces.

📚 Learning Resources

Apple and Swift

Community

Discovery

Prefer a recent official source when framework behavior, platform policy, security, privacy, or App Store requirements matter. Community material is most valuable for explanation, tradeoffs, and experience reports.

Contributing

Contributions are welcome.

Before adding a link or recommendation, check that:

  • It teaches a durable concept or solves a real iOS engineering problem.
  • The technical claim is current and can be verified.
  • The project is maintained or clearly labeled as legacy.
  • The description explains why the resource is useful.
  • A first-party framework does not already cover the need more simply.
  • The license, privacy, and security implications are acceptable.
  • The addition fits an existing section or justifies a new one.

Keep pull requests focused. When correcting a technical claim, include the official source used to verify it.

If this guide helps you, star the repository or open an issue with a concrete improvement.

Author

Created and maintained by Jungpyo Hong (Dennis).