Mobile Development 17 min read

Unlock Swift’s Memory Secrets: How HandyJSON Bypasses Runtime for Faster JSON Parsing

This article explores Swift's memory model and pointer mechanics, explains how HandyJSON converts JSON to class instances without runtime support, demonstrates MemoryLayout utilities, and shows practical techniques for modifying struct and class properties directly in memory.

Tencent TDS Service
Tencent TDS Service
Tencent TDS Service
Unlock Swift’s Memory Secrets: How HandyJSON Bypasses Runtime for Faster JSON Parsing
HandyJSON is an open‑source Swift library for converting JSON data into class or struct instances, similar to JSONModel . Because Swift lacks Objective‑C‑style runtime, HandyJSON bypasses runtime by directly manipulating instance memory to assign property values.

Memory Allocation

Stack: stores temporary value‑type variables and function call frames.

Heap: stores reference‑type instances.

MemoryLayout

Basic Usage

MemoryLayout

was introduced in Swift 3.0 to calculate the size of a type in memory.

MemoryLayout<Int>.size               // 8
let a: Int = 10
MemoryLayout.size(ofValue: a)      // 8

MemoryLayout Properties

MemoryLayout

provides three useful Int properties:

alignment & alignment(ofValue: T)

This reflects the memory‑alignment requirement; on a 64‑bit system the maximum alignment is 8 bytes.

size & size(ofValue: T)

The number of contiguous bytes occupied by an instance of T.

stride & stride(ofValue: T)

The distance between successive elements in an array of T, accounting for alignment.

Basic Data Types MemoryLayout

// Value types
MemoryLayout<Int>.size        // 8
MemoryLayout<Int>.alignment   // 8
MemoryLayout<Int>.stride      // 8

MemoryLayout<String>.size      // 24
MemoryLayout<String>.alignment // 8
MemoryLayout<String>.stride    // 24

// Reference type T
MemoryLayout<T>.size          // 8
MemoryLayout<T>.alignment     // 8
MemoryLayout<T>.stride        // 8

// Pointer types
MemoryLayout<UnsafeMutablePointer<T>>.size        // 8
MemoryLayout<UnsafeMutablePointer<T>>.alignment   // 8
MemoryLayout<UnsafeMutablePointer<T>>.stride      // 8

MemoryLayout<UnsafeMutableBufferPointer<T>>.size        // 16
MemoryLayout<UnsafeMutableBufferPointer<T>>.alignment   // 16
MemoryLayout<UnsafeMutableBufferPointer<T>>.stride      // 16

Swift Pointers

Common Swift Pointer Types

unsafePointer<T> ≈ const T *

Getting a Pointer to an Object

final func withUnsafeMutablePointers<R>(_ body: (UnsafeMutablePointer<Header>, UnsafeMutablePointer<Element>) throws -> R) rethrows -> R

var a: T = T()
let aPointer = a.withUnsafeMutablePointer { return $0 }

func headPointerOfStruct() -> UnsafeMutablePointer<Int8> {
    return withUnsafeMutablePointer(to: &self) {
        return UnsafeMutableRawPointer($0).bindMemory(to: Int8.self, capacity: MemoryLayout<Self>.stride)
    }
}

func headPointerOfClass() -> UnsafeMutablePointer<Int8> {
    let opaque = Unmanaged.passUnretained(self as AnyObject).toOpaque()
    let typed = opaque.bindMemory(to: Int8.self, capacity: MemoryLayout<Self>.stride)
    return UnsafeMutablePointer<Int8>(typed)
}

Struct Memory Model

Structs are value types stored on the stack.

struct Point {
    var a: Double
    var b: Double
}
MemoryLayout<Point>.size // 16

When a property becomes optional, the struct size increases due to alignment padding.

struct Point {
    var a: Double?
    var b: Double
}
MemoryLayout<Point>.size // 24
MemoryLayout<Double>.size // 8
MemoryLayout<Optional<Double>>.size // 9

Modifying a Struct Property via Memory

let animal = Animal()
let animalPtr: UnsafeMutablePointer<Int8> = animal.headPointerOfStruct()
let animalRawPtr = UnsafeMutableRawPointer(animalPtr)
let aPtr = animalRawPtr.advanced(by: 0).assumingMemoryBound(to: Int.self)
aPtr.pointee               // 1
aPtr.initialize(to: 100)
aPtr.pointee               // 100

Class Memory Model

Classes are reference types stored on the heap; the stack holds a pointer to the heap instance. The heap also stores type metadata and ARC reference count.

class Human {
    var age: Int?
    var name: String?
    var nicknames: [String] = []
    func headPointerOfClass() -> UnsafeMutablePointer<Int8> {
        let opaque = Unmanaged.passUnretained(self as AnyObject).toOpaque()
        let typed = opaque.bindMemory(to: Int8.self, capacity: MemoryLayout<Human>.stride)
        return UnsafeMutablePointer<Int8>(typed)
    }
}
MemoryLayout<Human>.size // 8

Modifying a Class Property via Memory

let human = Human()
let humanRawPtr = UnsafeMutableRawPointer(human.headPointerOfClass())
let nickPtr = humanRawPtr.advanced(by: 64).assumingMemoryBound(to: Array<String>.self)
nickPtr.initialize(["goudan","zhaosi","wangwu"])

Understanding V‑Table Dispatch

Swift uses a type pointer in each class instance that points to static type metadata containing a V‑Table. Method calls are resolved by looking up the method address in this table.

Swapping a Class’s Type Pointer

By overwriting the type pointer of an instance, you can make a Fox object behave like a Wolf object, causing method dispatch to invoke the wrong implementation.

let wolf = Wolf()
let fox = Fox()
let wolfPtr = UnsafeMutableRawPointer(wolf.headPointerOfClass())
let foxPtr = UnsafeMutableRawPointer(fox.headPointerOfClass())
foxPtr.advanced(by: 0).bindMemory(to: UnsafeMutablePointer<Wolf.Type>.self, capacity: 1).initialize(to: wolfPtr.advanced(by: 0).assumingMemoryBound(to: UnsafeMutablePointer<Wolf.Type>.self).pointee)
print(type(of: fox)) // Wolf
fox.soul() // "my soul is wolf"

These experiments demonstrate how Swift’s memory layout and type metadata can be inspected and manipulated at runtime.

SwiftMemory LayoutpointersstructunsafeclassJSON parsing
Tencent TDS Service
Written by

Tencent TDS Service

TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.

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.