Unveiling iOS Blocks: Memory Layout, Types, and Clang Conversion
This article dissects iOS blocks, explaining their struct‑based memory layout, the three block types, how they are transformed into C++ code with clang, and the impact of capturing variables—including value, static, global, and object references—on block behavior and lifecycle.
Overview
In iOS development a block is the language‑level implementation of a closure; it packages a piece of executable code together with any captured context so that the code can be passed around like data.
Memory Layout
A block is essentially a C struct whose fields appear in a fixed order:
isa : points to the block’s class object (e.g., __NSMallocBlock__).
flags : stores flag bits such as whether external variables are captured.
reserved : reserved for future compiler optimisations.
invoke : a function pointer to the block’s executable code.
descriptor (or desc): points to a block_desc_0 structure containing the block’s size, captured‑variable layout and pointers to copy/dispose helpers.
variables : the actual captured external variables.
Block Types
Blocks are classified into three runtime classes: __NSGlobalBlock__: does not capture any external variables; lives in the global data segment. __NSStackBlock__: created on the stack in MRC; must be copied to the heap before escaping. __NSMallocBlock__: heap‑allocated block managed by the runtime (ARC performs the copy automatically).
Conversion to C++ with clang
Using clang to rewrite Objective‑C source reveals the underlying struct representation. The typical command is:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc [source_file] -o [dest_file]Key flags: -fobjc-arc: tells clang to treat the source as ARC (or mixed ARC/MRC) code. -x objective-c++: required when the source contains Objective‑C++. -rewrite-objc: makes clang emit the equivalent C++ code instead of compiling it. [dest_file]: optional path for the generated .cpp file.
Conversion Example
A minimal block that captures no variables is compiled to a struct named __main_block_impl_0. After stripping the autogenerated boilerplate the relevant fields are:
struct __main_block_impl_0 {
void *isa;
int Block_size;
void (*FuncPtr)(void *);
};The block lives on the stack; ARC automatically copies it to the heap when needed.
Calling Mechanism
When a block is created the runtime constructs an instance of its implementation struct and stores the address of the function to execute in FuncPtr. Invoking the block is effectively a call through that pointer. In ARC the copy operation is performed automatically, moving the block from __NSStackBlock__ to __NSMallocBlock__ and incrementing the reference count.
External Variables
If a block captures an external variable, the struct gains an extra field for that variable. For a value‑type capture the value is copied into the struct; for a reference‑type capture the struct stores a pointer (or a pointer‑to‑pointer for static objects). The generated descriptor also records the capture kind so that the runtime can manage memory correctly.
Value Types
Captured primitive values are copied by value. To modify a captured value after the block is created you must mark the variable with __block, which causes the compiler to store a reference instead of a copy.
Static Variables
When a captured variable is declared static, the block stores a pointer to that static storage. No __block qualifier is required because the static object already lives for the program’s lifetime.
Global Variables
Global variables are not stored inside the block struct; the block simply accesses them directly, so the struct layout does not change.
Object‑Type Variables
When a block captures an Objective‑C object, the struct includes additional helper functions __main_block_copy_0 and __main_block_dispose_0. The copy helper calls Block_object_assign with a flag indicating whether the captured object is strong, weak, or unsafe, and the dispose helper calls Block_object_dispose to decrement the reference count or release the object as appropriate.
Conclusion
The article walks through the complete lifecycle of an iOS block—from its low‑level struct layout and type classification, through clang‑generated C++ representation, to the nuances of capturing different kinds of variables. A follow‑up article will cover the __block and __weak qualifiers in depth.
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.
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
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.
