Mobile Development 21 min read

Swift and Objective‑C Mixed Development in 58 Group’s Real‑Estate Business: Architecture, Module Integration, and Reflection Issues

This article details the background, current status, and engineering architecture of introducing Swift into 58 Group’s real‑estate iOS apps, explains the two main mixed‑compilation approaches (bridging header and module), presents practical module setup, discusses reflection pitfalls, binding solutions, and performance comparisons between Swift and Objective‑C implementations.

58 Tech
58 Tech
58 Tech
Swift and Objective‑C Mixed Development in 58 Group’s Real‑Estate Business: Architecture, Module Integration, and Reflection Issues

In 2014 Apple introduced Swift, and after the ABI stabilization in 2019 the language gained rapid adoption; 58 Group started a Swift co‑development project (the "混天" project) in late 2020 to build basic components, tools, and infrastructure, and to define Swift coding standards for its various business lines.

The real‑estate business line, a core part of the group, began integrating Swift alongside existing Objective‑C code because a full rewrite was infeasible. The team adopted a mixed‑development approach, combining Swift and Objective‑C within the same targets.

Engineering Architecture : The iOS team maintains dozens of apps (58同城, 安居客, 赶集网, etc.) and uses a component‑based architecture with shared SDKs. A middle layer abstracts differences between apps, allowing vertical business lines to share code.

Mixed‑Compilation Schemes :

Directed Bridging: Add a #import "ProductModuleName-Bridging-Header.h" file to expose Objective‑C headers to Swift and import #import -Swift.h in Objective‑C to use Swift classes. This method is simple but becomes unwieldy as the number of headers grows and does not work across CocoaPods modules.

Module: Enable Defines Module = YES in Build Settings, create an umbrella header that imports the required Objective‑C headers, and import the generated #import in Objective‑C. This approach supports cross‑module calls.

Module Practice :

#import "WBListVC.h"
@import WBLOCO;
@interface WBListVC ()
@property (nonatomic, strong) LCListView *listV;
@end

After enabling the module option in each podspec ( DEFINES_MODULE = YES ) and adding the appropriate dependencies, both Swift and Objective‑C files can import each other using @import statements. Swift interfaces exposed to Objective‑C must be marked @objc and declared public .

Swift Type Exposure :

import Foundation
@objc public enum LCListItemSelectionStyle: Int {
    case single
    case multiple
}
@objc public class LCListItemModel: NSObject {
    @objc public var list_selected: Bool = false
    @objc public var list_selection_style: LCListItemSelectionStyle = .single
    @objc public var text: String = ""
    @objc public var data: [LCListItemModel] = []
    @objc public convenience init(modelWithDict: [String:Any]) {
        self.init()
        LCListItemModel.init(dict: modelWithDict)
    }
}

Pitfalls Encountered :

Duplicate protocol or block names cause compilation failures when Swift’s stricter checking is applied.

LLDB debugging errors arise from non‑modular header imports; fixing them requires using full‑path imports (e.g., #import ).

Reflection with NSClassFromString fails for Swift classes because their mangled names include the module prefix (e.g., _TtC6KCObjc9TestClass ). Adding @objc(TestClass) forces the class to be exported with the plain name, making reflection work without knowing the module.

Reflection Investigation shows that the runtime looks up classes via objc_lookUpClass , which searches a map populated from the Mach‑O image. Swift classes without an explicit @objc name are stored with their mangled identifier, so NSClassFromString("TestClass") returns nil . Using @objc(TestClass) registers the class under the expected name, solving the issue.

Binding Solutions :

For key‑to‑widget binding, the team moved from +load methods (which increase launch time) to a Mach‑O segment approach for Objective‑C, and finally to a Swift‑compatible method using a BindKVCenter class with extensions that each implement an enter method. At runtime, the app enumerates all enter methods via class_copyMethodList and invokes them to register the bindings.

Class currentClass = [BindKVCenter class];
Method *methodList = class_copyMethodList(object_getClass(currentClass), &methodCount);
for (NSInteger i = 0; i < methodCount; i++) {
    Method method = methodList[i];
    NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(method)) encoding:NSUTF8StringEncoding];
    if ([@"enter" isEqualToString:methodName]) {
        IMP imp = method_getImplementation(method);
        ((void (*)(id, SEL))imp)(currentClass, method_getName(method));
    }
}
free(methodList);

Performance Comparison shows that Swift‑implemented carousel pages achieve similar FPS to Objective‑C, lower CPU usage under heavy load, but higher memory consumption due to the mixed environment. Overall code size is reduced by about 38% when using Swift.

Conclusion : Swift offers safety, performance, and productivity benefits over Objective‑C. Despite numerous integration challenges—module configuration, reflection handling, and binding mechanisms—the 58 Group’s real‑estate team successfully migrated key pages to Swift, increased developer proficiency, and plans to continue expanding Swift usage.

performanceiOSreflectionSwiftObjective-CModuleMixed Development
58 Tech
Written by

58 Tech

Official tech channel of 58, a platform for tech innovation, sharing, and communication.

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.