Optimizing JD Mall Order Business with Swift: Static Dispatch, Value Types, and Functional Techniques
This article describes how JD Mall’s order system migrated key iOS components to Swift, leveraging static dispatch, value‑type structures, protocol‑oriented design, error handling, guard statements, defer, lazy loading, and functional programming to improve performance, safety, and maintainability across mobile and macOS applications.
With Swift ABI stability, JD.com has increasingly adopted Swift for its order‑related iOS features, including order pages in the JD app, a logistics widget, and the internal macOS "JD Workstation" application.
During the migration the team highlighted Swift’s static dispatch, value‑type semantics, static polymorphism, error‑throwing, currying, and higher‑order functions, which address many pain points of Objective‑C such as tight class coupling, implicit data sharing, and thread‑unsafe reference counting.
Replace dynamic dispatch with static dispatch
Static dispatch (direct branch instructions on ARM) yields faster calls and better inlining. The team audited all NSObject subclasses, removed unnecessary inheritance, and used final or private where possible. Xcode 12’s LLVM also supports Obj‑C static dispatch via __attribute__((objc_direct)).
Prefer structs or enums over classes
Swift structs and enums are value types offering stack allocation, small memory footprint, copy‑on‑write, thread safety, and static dispatch. The team replaced many classes in the logistics widget and SwiftUI macOS app with structs/enums, noting benefits such as fast creation, no reference counting, and easier compiler optimizations.
Optimize struct memory layout
Memory size depends on property order; using MemoryLayout<T>.size the team demonstrated that a different field ordering can increase size (e.g., GameBoard 9 bytes vs. GameBoard2 12 bytes). They reviewed types to use the smallest appropriate primitive (Int32, Bool) and placed smaller fields later.
struct GameBoard {
var p1Score: Int32
var p2Score: Int32
var gameOver: Bool
}
struct GameBoard2 {
var p1Score: Int32
var gameOver: Bool
var p2Score: Int32
}
// MemoryLayout<GameBoard>.size // 9 bytes
// MemoryLayout<GameBoard2>.size // 12 bytesUse static polymorphism instead of dynamic polymorphism
By constraining generic parameters to protocols, the compiler can resolve method calls at compile time, enabling better optimization under Whole‑Module Optimization (WMO). Example code shows a protocol‑based draw function that compiles only when the concrete type conforms.
protocol Drawable {
func draw()
}
struct Line: Drawable {
var x: Double = 0
func draw() { }
}
func drawACopy<T: Drawable>(local: T) {
local.draw()
}
let line = Line()
drawACopy(local: line) // succeeds
// let line2: Drawable = Line() // compile‑time errorProtocol extensions for default implementations
Swift prefers protocol‑oriented programming; extensions provide default method bodies, reducing the need for class inheritance and allowing the compiler to inline static calls.
Improve error handling
Swift’s Error protocol and throws enable clearer APIs. The team uses enum‑based errors and demonstrates rethrows in standard library functions like map.
enum CustomError: Error {
case error1
case error2
}
let a: (Int) throws -> Void = { n in }
let b: (Int) -> Void = { n throws in } // compile‑time errorGuard statements to reduce nesting
Guard clauses early‑exit on failure, improving readability compared to deep if nesting.
guard let value1 = dict["key"], value1 == "0" else { return }
guard let value2 = dict["key2"], value2 == "0" else { return }
print("\(value1) \(value2)")Defer for cleanup
Deferred closures run when the surrounding scope exits, useful for closing files, releasing locks, or other cleanup tasks.
func write() throws {
guard let file = FileHandle(forUpdatingAtPath: filepath) else {
throw WriteError.notFound
}
defer { try? file.close() }
// write operations
}Replace forced unwraps with optional binding
Using if let or guard let eliminates unsafe ! usage and clarifies intent.
var optString: String?
if let _ = optString {
// safe usage
}Lazy loading for expensive properties
Mark rarely‑used properties as lazy to defer initialization until first access.
lazy var aLabel: UILabel = {
let label = UILabel()
return label
}()Functional programming to reduce state
Swift functions can be passed around, curried, and composed, allowing developers to avoid mutable state. The article shows examples of curried addition/multiplication and a custom operator for function composition.
func add(_ a: Int) -> (Int) -> Int { { $0 + a } }
func multiple(_ a: Int) -> (Int) -> Int { { $0 * a } }
infix operator > : AdditionPrecedence
func > (f1: @escaping (Int) -> Int, f2: @escaping (Int) -> Int) -> (Int) -> Int {
{ f2(f1($0)) }
}
let n = 3
let newFn = add(7) > multiple(6)
print(newFn(n)) // 60Conclusion
Swift’s expressive syntax, strong type inference, and modern language features make it easy to adopt, but achieving high performance and clean APIs still requires disciplined engineering. JD’s order team reports improved development speed and stability across iOS widgets, AppClips, and macOS desktop tools, and the company is expanding internal Swift infrastructure.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
