How to Migrate Objective C to Swift: Best Practices, Apple Tools, and Converter Options

The most reliable way to migrate Objective C to Swift is using Apple's built-in Swift Migrator (accessible via Xcode's Migration Assistant or command-line swiftc), which applies API-diff fix-its and preserves Objective-C visibility with the -migrate-keep-objc-visibility flag, supplemented by third-party converters like Swiftify for initial bootstrapping.

Migrating a large Objective-C codebase to Swift requires a strategic blend of automated tooling and manual refinement. The Swift compiler ships with a sophisticated migration engine located in lib/Migrator/ that handles API changes and Objective-C interoperability annotations. This guide examines the official migration pipeline implemented in the apple/swift repository, command-line workflows, and third-party converter options to help you migrate Objective C to Swift with minimal disruption.

Understanding the Official Swift Migrator Architecture

The Swift compiler includes a dedicated migrator pipeline that processes source files through pre-fix-it, AST, and post-fix-it passes to modernize syntax and handle SDK changes.

Core Components

The migrator relies on several key components:

  • API-diff JSON files: These define how APIs have changed between Swift versions, stored in the SDK at paths like $SDK_ROOT/usr/lib/swift/ide/SwiftOverlay/Overlay.json.
  • Remap files: The migrator generates *.remap files that contain the textual differences between the original and migrated code.
  • Fix-it engine: Applies automated corrections based on API-diff data and compiler diagnostics.

Key Source Files in the Swift Repository

According to the apple/swift source code, these files define the migration behavior:

File Purpose
lib/Migrator/README.md Overview of the migrator pipeline, flags, and usage details
lib/Driver/ToolChains.cpp (line 634) Implements the -migrate-keep-objc-visibility flag
include/swift/Option/Options.td (line 1367) Declares command-line options like -emit-migrated-file-path and -dump-migration-states-dir
test/Driver/driver_migration.swift Verifies that migration flags propagate correctly through the driver
test/Migrator/override_migration.swift Demonstrates API-diff migration with Objective-C visibility preservation

Command-Line Migration Workflow

For large projects, running the migrator via command line provides better automation and CI/CD integration than the Xcode GUI.

Essential Migration Flags

The swiftc driver supports several flags defined in include/swift/Option/Options.td:

  • -update-code: Enables the migration mode.
  • -emit-migrated-file-path <path>: Specifies where to write the migrated source file.
  • -dump-migration-states-dir <dir>: Outputs intermediate migration states and remap files for inspection.
  • -migrate-keep-objc-visibility: Preserves Objective-C runtime visibility by adding @objc to declarations that were implicitly exposed in previous Swift versions. This flag is processed in lib/Driver/ToolChains.cpp.
  • -api-diff-data-file <path>: Points to the API-diff JSON describing SDK changes.

Practical Command-Line Example

To migrate a specific module while preserving Objective-C interoperability:

swiftc -typecheck -update-code \
       -emit-migrated-file-path NetworkingMigrated.swift \
       -dump-migration-states-dir ./migration-states \
       -migrate-keep-objc-visibility \
       -api-diff-data-file $SDK_ROOT/usr/lib/swift/ide/SwiftOverlay/Overlay.json \
       Sources/Networking/**/*.swift Sources/Networking/**/*.h

This command generates NetworkingMigrated.swift containing modernized Swift code and a ./migration-states/*.remap file showing the textual differences. The -migrate-keep-objc-visibility flag ensures that any declarations previously visible to Objective-C retain their @objc attribute, preventing runtime failures in mixed codebases.

Using Xcode's Migration Assistant

Xcode provides a graphical interface that invokes the same underlying migrator engine found in lib/Migrator/.

The Migration Assistant workflow:

  1. Open the project in Xcode 15 or later.
  2. Choose Edit → Convert → To Current Swift Syntax.
  3. Select the targets to migrate. Xcode analyzes the selected code using the same API-diff JSON files and fix-it passes described in lib/Migrator/README.md.
  4. Enable "Preserve Objective-C visibility" in the dialog, which maps to the -migrate-keep-objc-visibility flag.
  5. Review the preview, which displays the remap differences generated by the migrator, apply the changes, and rebuild.

This UI approach is ideal for smaller modules or initial exploration, while the command-line workflow better suits CI/CD pipelines and large-scale automation.

Handling Objective-C Interoperability

Maintaining seamless interoperability between Swift and remaining Objective-C code is critical during incremental migration.

Preserving Visibility with @objc

Swift 4 removed implicit Objective-C exposure for many declarations. The migrator's -migrate-keep-objc-visibility flag, implemented in lib/Driver/ToolChains.cpp, automatically adds @objc to declarations that previously had default Objective-C visibility.

When manually managing visibility without this flag, you must explicitly annotate declarations:

@objcMembers
class MyLegacyViewController: UIViewController {
    @objc func buttonTapped(_ sender: Any) {
        // Implementation
    }
}

The @objcMembers attribute exposes all members to the Objective-C runtime, while individual @objc annotations provide granular control.

Modular Migration Strategy

For large codebases, adopt a modular approach:

  1. Isolate functionality into static libraries or Swift packages that compile independently.
  2. Create bridging headers for Objective-C modules that must remain accessible to Swift.
  3. Migrate one module at a time, using the migrator on isolated codebases to reduce complexity.
  4. Maintain binary compatibility by keeping Objective-C headers stable while Swift implementations evolve.

This approach minimizes risk and allows teams to validate each migrated component before proceeding.

Third-Party Converter Options

While Apple's official migrator handles Swift-to-Swift updates and SDK changes, several third-party tools can assist with initial Objective-C to Swift translation.

Swiftify

Swiftify offers both online and command-line interfaces for converting Objective-C code to Swift. It handles many language constructs automatically and integrates with Xcode via extensions.

Strengths:

  • Fast bulk conversion of Objective-C syntax
  • Handles common patterns and language constructs
  • Xcode integration for workflow convenience

Limitations:

  • Generates "best-effort" code requiring manual cleanup
  • Struggles with complex memory-management semantics
  • Limited handling of custom macros and preprocessor directives

objc2swift

This open-source command-line tool converts Objective-C directories to Swift while respecting custom header configurations.

Strengths:

  • Works on entire directory structures
  • Respects custom header search paths
  • No cost or licensing restrictions

Limitations:

  • Less maintained than commercial alternatives
  • Limited support for modern Swift generics and protocols
  • May not handle latest Objective-C language features

Recommendation

Use third-party converters only to create initial drafts for pure Objective-C files without heavy dynamic dispatch or complex macro usage. Always follow up with Apple's official migrator to apply SDK-specific changes and proper @objc annotations. For production codebases, prioritize the official swiftc migrator and Xcode Migration Assistant over automated translation tools.

Summary

  • Apple's Swift Migrator, located in lib/Migrator/ and accessible via swiftc or Xcode, provides the most accurate migration path for modernizing Swift code and handling SDK changes.
  • The -migrate-keep-objc-visibility flag, implemented in lib/Driver/ToolChains.cpp at line 634, preserves Objective-C runtime compatibility by automatically adding @objc to previously exposed declarations.
  • Command-line migration using flags like -emit-migrated-file-path and -api-diff-data-file enables CI/CD integration and batch processing of large codebases.
  • Modular migration strategies reduce risk by isolating functionality into independent libraries, migrating one module at a time while maintaining stable Objective-C headers.
  • Third-party converters like Swiftify and objc2swift can bootstrap initial translation but require cleanup and official migrator passes for production quality.

Frequently Asked Questions

What is the difference between Apple's Swift Migrator and third-party Objective-C to Swift converters?

Apple's Swift Migrator is a compiler-integrated tool designed to update Swift code between language versions and handle SDK API changes, while third-party converters like Swiftify translate Objective-C syntax into Swift. The official migrator produces compiler-verified code that respects Apple's SDK evolution and Objective-C interoperability requirements, whereas third-party tools generate draft code that often requires significant manual correction for memory management and dynamic dispatch scenarios.

How do I preserve Objective-C interoperability when migrating to Swift?

Use the -migrate-keep-objc-visibility flag when running the Swift Migrator from the command line, or enable "Preserve Objective-C visibility" in Xcode's Migration Assistant. This flag, processed in lib/Driver/ToolChains.cpp, automatically adds @objc attributes to declarations that were implicitly visible to Objective-C in previous Swift versions. For manual control, apply @objc to individual methods or @objcMembers to classes to maintain runtime visibility for remaining Objective-C code.

Can I automate the migration process for a large codebase in CI/CD pipelines?

Yes, the Swift Migrator supports full command-line automation through swiftc with flags like -update-code, -emit-migrated-file-path, and -dump-migration-states-dir. You can integrate these commands into CI/CD workflows to migrate modules automatically and generate remap files for review. However, due to the complexity of Objective-C semantics and potential for ambiguous constructs, automated migrations should always include manual code review and comprehensive test suite validation before deployment.

What are the limitations of using third-party converters like Swiftify?

Third-party converters generate "best-effort" Swift code that often requires substantial manual cleanup, particularly around memory-management semantics (MRC versus ARC), custom preprocessor macros, and complex dynamic dispatch patterns. They often lack support for the latest Swift language features like modern generics and concurrency, and they do not integrate with Apple's API-diff system or automatically add necessary @objc annotations. Use these tools only for initial bootstrapping of pure Objective-C files, then apply Apple's official migrator for SDK-specific updates.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →