Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C: How is ARC Enabled Within GNUStep?

Objective-C/ARC/memory managements questions have been done to death on SO, but this one seems slightly different to the existing ones.

I've been trying to use Objective-C with GNUStep and Clang. I've downloaded the libraries apparently required for modern Objective-C features like ARC; blocks work and @autoreleasepools are accepted by the compiler along with the associated compiler flag. The AppKit GUI toolkit works, and so does the queue dispatcher.

My understanding, if correct, is that alloced objects are automatically set up to release upon the exiting of a @autoreleasepool of a 'parent' stack frame, and that releasing decrements a reference count. Yet the compiler doesn't bemoan a manual [super dealloc] and tolerates manual autoreleases and releases, which implies that ARC isn't even switched on.

One might imagine that Googling GNUStep ARC ~enable would yield some compiler flag that I'm missing out, but it doesn't.

Here's some example code. It's an object wrapper around a multiple dimensional array of C99 bools, which is malloced in init and freed within dealloc, which I gather is one of the few legitimate uses of dealloc within ARC code. Notice that dealloc's puts is not called after the @autoreleasepool finishes, despite there only being a single reference created within it. A manual release or autorelease, however, works great.

#import <stdbool.h>
#import <stdio.h>
#import <stdlib.h>

#import <Foundation/Foundation.h>

@interface Area : NSObject {
    bool *area;
    size_t width, height;
}

- (id) initWithWidth:(size_t)aWidth height:(size_t)aHeight;
- (void) dealloc;
- (void) display;
@end

@implementation Area

- (id) initWithWidth:(size_t)aWidth height:(size_t)aHeight {
    self = [super init];
    width = aWidth;
    height = aHeight;
    area = malloc((sizeof *area) * aWidth * aHeight);

    for (size_t y = 0; y < aHeight; ++y) {
        for (size_t x = 0; x < aWidth; ++x) {
            area[(aHeight * y) + (aWidth * x)] = true;
        }
    }

    return self;
}

- (void) dealloc {
    free(area);
    puts("DEALLOCATED");
}

- (void) display {
    for (size_t y = 0; y < height; ++y) {
        putchar('|');
        for (size_t x = 0; x < width; ++x) {
            putchar(area[(height * y) + (width * x)]
                    ? '#'
                    : ' ');
        }
        puts("|");
    }
}

@end

int main(void)
{
    @autoreleasepool {
        id area = [[Area alloc] initWithWidth:10 height:10];
        [area display];
    }
    return EXIT_SUCCESS;
}

My compiling script (I'll use a proper makefile once I've got this working):-

#!/bin/sh

INC_FLAG=`gnustep-config --variable=GNUSTEP_SYSTEM_HEADERS`
LIB_FLAG=`gnustep-config --variable=GNUSTEP_SYSTEM_LIBRARIES`

clang -o main main.m \
    -I $INC_FLAG \
    -L $LIB_FLAG \
    \
    -fblocks \
    -fobj-arc \
    -fconstant-string-class=NSConstantString \
    -D_NATIVE_OBJC_EXCEPTIONS \
    \
    -pthread \
    -lgnustep-base \
    -ldispatch \
    -lgnustep-gui \
    -lobjc

I've been under the assumption that autorelease should be inferred for objects created within @autoreleasepool.

Thanks in advance!

like image 490
Louis Jackman Avatar asked Nov 10 '13 22:11

Louis Jackman


1 Answers

Solution: Josh Caswell pointed out that my compiler flag fobj-arc should be fobjc-arc. Given that Clang gave no indicator of this flag being invalid, I'll leave this answer up for anyone else.

like image 91
Louis Jackman Avatar answered Nov 03 '22 21:11

Louis Jackman