objective-cmemory-managementheap-memoryalloc

Are objects in Objective-C ever created on the stack?


As far as I understand, in C++ you can create objects on the stack:

SomeClass object = SomeClass();

or on the heap:

SomeClass *object = new SomeClass();

In Objective-C you always seem to create objects on the heap, as [SomeClass alloc] returns a pointer to a new instance. Is this correct?

Are objects ever allocated on the stack? If so, what would be a good example? Else, why not?


Solution

  • 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.)