Game Development 27 min read

Swift Native Mini‑Game Development in the Same‑City App: Architecture, Mixed‑Language Integration, and Performance Optimizations

This article describes how the Same‑City team migrated H5 mini‑games to a native Swift/SpriteKit solution, detailing the mixed Objective‑C/Swift environment, core game architecture, use of Swift functional and generic features, and the resulting improvements in package size, startup time, FPS, and memory consumption.

58 Tech
58 Tech
58 Tech
Swift Native Mini‑Game Development in the Same‑City App: Architecture, Mixed‑Language Integration, and Performance Optimizations

The Same‑City (同城) product originally used H5 mini‑games, but Apple’s 4.7.7 review policy prohibited the cash‑reward mechanic, forcing the team to seek a native solution. To comply while preserving user engagement, they decided to rewrite the game in Swift.

58 Group’s Swift infrastructure platform aims to promote Swift across the app, providing mixed‑language compilation, build‑time optimization, and package‑size detection. This project served as a practical case for applying those capabilities.

Industry research showed most mini‑games still rely on H5, with a few using React Native or embedding OpenGL/EJJavaScriptView. The team therefore set out to build a native game quickly.

Rapid team building was achieved through three steps: (1) fast learning by rewriting the Same‑City homepage in Swift to gain hands‑on experience; (2) quickly mastering SpriteKit by studying official docs and open‑source examples to implement core scenes such as the car and house layout; (3) dividing tasks among multiple developers, tracking daily progress, and ensuring smooth overall development.

Mixed‑language environment was established by creating a bridge header for each pod (Pod‑Name‑Bridge‑Header.h) to expose Objective‑C classes to Swift, and generating a Pod‑Name‑Swift.h file to call Swift from Objective‑C. Public Swift APIs were marked with @objc. Modules were enabled via DEFINES_MODULE = YES in podspecs, allowing other pods to import Swift code with @import.

Game implementation details include:

Game scene is a subclass of SKScene presented by an SKView:

override func viewDidLoad() {
    super.viewDidLoad()
    let skView = SKView(frame: view.bounds)
    view.addSubview(skView)
    let gameScene = GameScene(size: view.bounds.size)
    skView.presentScene(gameScene)
}

Central 12‑grid layout is handled by GridNode (subclass of SKNode) with a position(for:) helper to compute coordinates.

func position(for location: Int) -> CGPoint {
    let index = location - 1
    let column = CGFloat(index % 3)
    let row = CGFloat(index / 3)
    let x = groundNodeWidth / 2 + (groundNodeWidth + nodeMargin) * column
    let y = -groundNodeHeight / 2 - groundNodeHeight * row
    return CGPoint(x: x, y: y)
}

Each grid cell contains a GroundNode (subclass of SKSpriteNode) which can host a HouseNode (also SKSpriteNode) representing different house levels.

private func addElement(level: Int) {
    let node = ElementNode(size: self.size, level: level)
    houseNode = node
    node.position = CGPoint(x: 0, y: -groundNodeHeight / 2)
    addChild(node)
}

Swift language features used throughout the project include functional programming ( reduce, filter, map, compactMap) for layout calculations and data filtering, and generics for API design and network result handling:

struct NetworkResult<T: Codable>: Codable where T: Codable {
    enum CustomKeys: String, CodingKey { case code, message, result }
    var code: Int?
    var message: String?
    var result: T?
}

Generic popup presentation is also demonstrated:

func show<T: Config, V: CenterConfig & AnimatedView>(with data: T, content: V.Type) {
    let window = Popup(frame: view.bounds)
    let promotion = content.init(frame: .zero)
    view.addSubview(window)
    window.centerContent = promotion
    window.config(with: data)
    window.showContent(animated: true)
}

Performance benefits observed after migration:

Package size reduced by ~4.7 MB thanks to on‑demand resource download.

Cold‑start time for the game scene dropped below 2 seconds (over 3× faster than the H5 version).

FPS increased by at least 15 % across scenarios due to Swift’s execution speed.

Memory usage decreased by >20 % because Swift favors value types and ARC over GC.

Resource pre‑loading strategy downloads a configuration table at app launch, caches updated assets, and loads them instantly when the user enters the game, achieving a 70 % reduction in first‑enter latency.

In summary, the case shows that mixing Objective‑C and Swift lowers the cost of adopting Swift, SpriteKit + Swift provides a low‑learning‑curve yet powerful native mini‑game framework, and dynamic resource loading solves package‑size constraints while delivering a near‑instant user experience.

For readers interested in the underlying tools, the team’s open‑source Mach‑O performance suite (WBBlades) is available at https://github.com/wuba/WBBlades . The authors also invite candidates to join the 58 同城 team (contact: [email protected]).

Performance optimizationiOSgame developmentGenericsSwiftFunctional ProgrammingMixed LanguageSpriteKit
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

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.