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

> Easily migrate Objective C to Swift using Apple's Swift Migrator and Xcode tools. Discover best practices and converter options for a seamless project transition.

- Repository: [Apple/swift](https://github.com/apple/swift)
- Tags: migration-guide
- Published: 2026-02-16

---

**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`](https://github.com/apple/swift/blob/main/lib/Migrator/README.md) | Overview of the migrator pipeline, flags, and usage details |
| [`lib/Driver/ToolChains.cpp`](https://github.com/apple/swift/blob/main/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`](https://github.com/apple/swift/blob/main/test/Driver/driver_migration.swift) | Verifies that migration flags propagate correctly through the driver |
| [`test/Migrator/override_migration.swift`](https://github.com/apple/swift/blob/main/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`](https://github.com/apple/swift/blob/main/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:

```bash
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`](https://github.com/apple/swift/blob/main/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`](https://github.com/apple/swift/blob/main/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`](https://github.com/apple/swift/blob/main/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:

```swift
@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`](https://github.com/apple/swift/blob/main/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`](https://github.com/apple/swift/blob/main/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.