The short answer is that objects are always allocated on the heap, not on the stack.
This isn't quite the whole story though. In Objective-C, blocks are also full Objective-C objects. They're peculiar in that they are sometimes on the stack. In particular, blocks created with the block literal syntax, and which reference surrounding scope, are on the stack. You can even see this if you inspect their class, which will be (the private) NSStackBlock
. If you copy them, with Block_copy()
or -copy
, the resultant copy will be on the heap (NSMallocBlock
).
One implication of this is that stack-allocated blocks are only valid until the end of the scope in which they were created. Prior to ARC (and IIRC in early version of ARC as well), this meant that you had to copy blocks that you wanted to live past their creation scope so they'd be on the heap. ARC handles this for you in most cases now, and also means that whether a block is on the stack or the heap is harder to predict.
This small test program shows this (compile with ARC off):
#import <Foundation/Foundation.h>
// Compile this without ARC.
int main(int argc, char *argv[]) {
@autoreleasepool {
NSMutableString *string = [NSMutableString stringWithString:@"foo"];
void(^stackBlock)() = ^{
[string setString:@"bar"];
};
NSLog(@"stackBlock class: %@", NSStringFromClass([stackBlock class]));
void(^heapBlock)() = [[stackBlock copy] autorelease];
NSLog(@"heapBlock class: %@", NSStringFromClass([heapBlock class]));
}
}
Output:
stackBlock class: __NSStackBlock__
heapBlock class: __NSMallocBlock__
(Just to be clear, you certainly shouldn't use a check for NSStackBlock
/NSMallocBlock
in real code. They're private implementation detail classes. This code is just for demonstration.)