Master Objective‑C Blocks: Types, __block, ARC/MRC Differences & Lifecycle
This article explains what Objective‑C blocks are, how they function as objects, the three block types, the role of the __block keyword, differences between ARC and MRC, and best practices for managing block lifecycles to avoid memory leaks.
Introduction
Before diving in, the author poses several questions about blocks and references a previous article by Tang Qiao, from which some diagrams and code are reused.
What Is a Block? Is It an Object?
A block is the Objective‑C implementation of a closure: a function (or a pointer to a function) together with its surrounding context variables. Consequently, a block is an object, as evidenced by the presence of an
isapointer in its internal
Block_layoutstructure.
Block Types and the __block Keyword
Blocks come in three concrete forms:
NSConcreteGlobalBlock – used when the block captures no external variables.
NSConcreteStackBlock – used when the block captures external variables.
NSConcreteMallocBlock – created when a block is copied (e.g., via
copy).
NSConcreteGlobalBlock is a global block determined at compile time, similar to a macro.
NSConcreteStackBlock holds a structure (
__main_block_impl_0) that stores captured variables, making it larger and dynamic. It does not retain the captured objects, as shown by the unchanged reference count in the log.
NSConcreteMallocBlock appears when a block is copied; it retains external objects.
The __block Keyword
An example demonstrates that without
__block, external variables are copied into the block; with
__block, the block captures the variable’s address, allowing modifications inside the block to affect the original variable.
In MRC, using
__blockdoes **not** copy the referenced object; it merely copies the pointer. In ARC, a
__blockvariable is retained inside the block, which can lead to retain cycles if not handled carefully.
Blocks in ARC vs. MRC
Under ARC, only NSConcreteGlobalBlock and NSConcreteMallocBlock typically appear because the default assignment is
strong, which triggers a copy, turning a stack block into a malloc block. This can cause retain cycles when a malloc block retains an object that also retains the block.
Block Lifecycle
Improper block usage can lead to memory leaks. A typical retain cycle occurs when an object holds a block (often an NSConcreteMallocBlock) and the block captures the object. The solution is to use
weakreferences in ARC or appropriate __block handling in MRC.
Do Blocks Strongly Reference Parameters?
Blocks, like functions, do not retain objects passed as parameters. This is demonstrated with a log showing unchanged reference counts.
Conclusion
Understanding the internal mechanics of Objective‑C blocks—types, the __block keyword, ARC/MRC behavior, and lifecycle management—is essential for senior developers to write safe and efficient iOS code.
Weidian Tech Team
The Weidian Technology Platform is an open hub for consolidating technical knowledge. Guided by a spirit of sharing, we publish diverse tech insights and experiences to grow and look ahead together.
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.