Mobile Development 17 min read

Baidu App Objective-C/Swift Mixed Programming Practice - Component Transformation and Interoperability

To enable Objective‑C and Swift mixed programming in Baidu App, static libraries are converted to static frameworks, module stability is activated, headers are module‑ized and dependencies declared via EasyBox, allowing safe inter‑component calls, proper nullability handling, and encouraging broader Swift adoption across the codebase.

Baidu App Technology
Baidu App Technology
Baidu App Technology
Baidu App Objective-C/Swift Mixed Programming Practice - Component Transformation and Interoperability

This article continues from the previous engineering practices to introduce Baidu App's Objective-C/Swift mixed programming transformation practices in componentization.

After Baidu App's componentization and binary transformation, the main compilation outputs are static_framework and static_library. With Swift 5.0 ABI stability, the operating system unified ABI standards, but ABI stability alone is not sufficient for binary framework distribution. Swift 5.1 introduced Module Stability, enabling binaries generated by different Swift compiler versions to work in the same application.

1. static_library Issues

In Xcode, setting BUILD_LIBRARY_FOR_DISTRIBUTION to YES in static_framework enables Module Stability. However, in static_library, this setting causes the error "using bridging headers with module interfaces is unsupported". Bridging headers are incompatible with Swift's binary interface files (.swiftinterface), making Module Stability impossible. Therefore, static_library must be transformed to static_framework to support mixed programming and binary compatibility.

2. Component Framework Transformation

The transformation involves: (1) Converting static_library to static_framework using EasyBox tool; (2) Modifying header file references from #import "ComponentA.h" to #import <ComponentA/ComponentA.h> .

3. Remove Precompiled Headers and Standardize Public Headers

Precompiled headers (PCH) have two problems: they cannot be part of binary components, and when static_library is transformed to static_framework, it causes compilation errors due to missing header references. Solution: remove PCH files and standardize component public headers.

4. Component Module-ization

LLVM Module changes traditional C-based language header mechanisms and is adopted by Swift. Without module-ization, Swift cannot call the component. The compilation output includes Headers, Info.plist, Modules (containing .swiftmodule, .swiftdoc, .swiftinterface, .swiftsourceinfo), and _CodeSignature.

5. Solving Inter-component Dependency Transmission

Swift Module requires explicit dependencies that are transmitted. If component A depends on B, and B depends on C with B's public header referencing C, then B transmits dependency on C. Solutions: (1) Add direct dependency on C in A; (2) Use EasyBox's module_dependency to declare transmitted dependencies.

6. Enable Module Stability

Set BUILD_LIBRARY_FOR_DISTRIBUTION to YES in static_framework's Build Settings.

7. Mixed Programming Within Components

In static_framework, Swift accesses Objective-C's public types through module files, while Objective-C accesses Swift's public types through #import <ProductName/ProductModuleName-Swift.h> . Private headers that need to be called by Swift must be changed to public headers.

8. Ideal State

The ideal state is a single component using pure Swift. For inter-component mixed programming, components will ultimately be either Swift or Objective-C, with simple calling methods using direct import.

Interoperability

1. Objective-C APIs Available in Swift

Xcode can generate Swift interfaces from Objective-C headers via Related Items button.

2. Nullability for Objective-C

Without NS_ASSUME_NONNULL_BEGIN/END, Objective-C properties/methods become implicitly unwrapped optionals in Swift, potentially causing crashes. Adding these annotations makes them non-optional in Swift, preventing crashes.

3. Safe Collection Types

NSArray without type specification becomes [Any] in Swift, requiring type checking with as? . Using generics like NSArray<UIView *> becomes [UIView] in Swift for safer access.

4. Mixed Programming Keywords

@objc : Exposes Swift methods to Objective-C

@objc(name) : Renames exposed methods

@nonobjc : Prevents exposure to Objective-C

@objcMembers : Implicitly adds @objc to all properties/methods

dynamic : Enables dynamic dispatch using Objective-C Runtime

NS_SWIFT_UNAVAILABLE : Makes APIs unavailable in Swift

NS_SWIFT_NAME : Renames APIs in Swift

NS_REFINED_FOR_SWIFT : Refines APIs for better Swift integration

Common Issues

Swift framework module name matching class name causes .swiftinterface bugs

Non-modular headers in framework cause "include of non-modular header inside framework module" errors - all components called by Swift must be module-ized

static_library called from static_framework must be module-ized; incorrect header写法 causes "Error while loading Swift module"

Cycle Reference: When Objective-C header references Swift header in bridging/umbrella header before Swift compilation completes, it causes build errors. Solution: maintain unidirectional references and use forward declarations.

Summary

With Apple's push for Swift and community support, Swift adoption is inevitable. Baidu App, with EasyBox toolchain support, has 30% of business components using Swift mixed programming. Service layer and lower components (55% of total) can use Swift mixed programming. The article recommends iOS developers upgrade their technical stack to Swift.

iOS DevelopmentSwiftcomponentizationframeworkObjective-CinteroperabilityBinary DistributionModule Stability
Baidu App Technology
Written by

Baidu App Technology

Official Baidu App Tech Account

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.