Howto: Programming in Objective-C without any framework

obsigna

Daemon

Reaction score: 863
Messages: 1,259

I was in need to revamp a quite old and quite large (>10000 lines) Objective-C project for deploying it on FreeBSD. The classes were all descendants of NSObject. So, I looked into using lang/gnustep-base, however:
# pkg install gnustep-base
Code:
...
The following 32 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
    gnustep-base: 1.24.8_5
    avahi-app: 0.6.31_5
    gnome_subr: 1.0
    dbus-glib: 0.104
    dbus: 1.8.20
    libX11: 1.6.4,1
    xproto: 7.0.28
    libXdmcp: 1.1.2
    libxcb: 1.11.1
    libpthread-stubs: 0.3_6
    libXau: 1.0.8_3
    kbproto: 1.0.7
    libICE: 1.0.9_1,1
    libSM: 1.2.2_3,1
    glib: 2.46.2_3
    python27: 2.7.12
    libffi: 3.2.1
    libiconv: 1.14_9
    pcre: 8.39
    gobject-introspection: 1.46.0
    python2: 2_3
    libdaemon: 0.14_1
    libobjc2: 1.8.1
    gnustep-make: 2.6.7_2
    gmp: 5.1.3_3
    gnutls: 3.4.16
    nettle: 3.2
    libtasn1: 4.9
    trousers: 0.3.13_1
    tpm-emulator: 0.7.4_1
    p11-kit: 0.23.2
    libidn: 1.33_1

Number of packages to be installed: 32

The process will require 151 MiB more space.
27 MiB to be downloaded.

Proceed with this action? [y/N]:

NOOOOOOooooooo#@$%^~?!!!!!

Fortunately, it turned out that all this is not necessary for basic Objective-C programming.

From the ports only the Objective-C runtime lang/libobjc2 is needed, and clang(1) and lldb(1), both in the FreeBSD base, are well suited to compile and debug Objective-C programs.

# pkg install libobjc2
Code:
...
The following 1 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
    libobjc2: 1.8.1

Number of packages to be installed: 1

67 KiB to be downloaded.

Proceed with this action? [y/N]:
YEEEEEESSSSssss!!!!!

Now only our own Objective-C root class is missing for getting started, here it is:

BareClass.h
Code:
#if __PTR_WIDTH__ == 32
   #pragma pack(4)
#else
   #pragma pack(8)
#endif

__attribute__((objc_root_class))
@interface BareClass
{
   Class isa;
   int   refcount;
}

+ (Class)class;
+ (Class)superclass;
+ (id)allocWithZone:(void *)zone;
+ (id)alloc;
+ (id)new;

- (Class)class;
- (Class)superclass;

- (id)init;
- (id)copy;
- (id)copyWithZone:(void *)zone;

- (id)retain;
- (void)release;
- (void)dealloc;

- (BOOL)isKindOfClass:(Class)aClass;
- (BOOL)isMemberOfClass:(Class)aClass;

@end
BareClass.m
Code:
#import <objc/Object.h>
#import "BareClass.h"

@implementation BareClass

+ (Class)class
{
   return self;
}

+ (Class)superclass
{
  return class_getSuperclass(self);
}

+ (id)allocWithZone:(void *)zone
{
   return class_createInstance(self, 0);
}

+ (id)alloc
{
   return [self allocWithZone:NULL];
}

+ (id)new
{
   return [[self alloc] init];
}

- (Class)class
{
    return object_getClass(self);
}

- (Class)superclass
{
  return class_getSuperclass(object_getClass(self));
}

- (id)init
{
   return self;
}

- (id)copy
{
   return [self copyWithZone:NULL];
}

- (id)copyWithZone:(void *)zone
{
   return self;
}

- (id)retain
{
   __sync_fetch_and_add(&refcount, 1);
   return self;
}

- (void)release
{
   if (__sync_sub_and_fetch(&refcount, 1) < 0)
      [self dealloc];
}

- (void)dealloc
{
   object_dispose(self);
}

- (BOOL)isKindOfClass:(Class)aClass
{
   Class me = object_getClass(self);

   while (me != nil)
   {
      if (aClass == me)
         return YES;
      me = class_getSuperclass(me);
   }

   return NO;
}

- (BOOL)isMemberOfClass:(Class)aClass
{
   return (object_getClass(self) == aClass) ? YES : NO;
}

@end
And here comes the inevitable "Hello, World!" app.
hello.m
Code:
#import <objc/Object.h>
#import "BareClass.h"

@interface Hello : BareClass
{
   char hello[16];
}

- (void)sayHello;

@end

@implementation Hello

- (id)init
{
   if (self = [super init])
   {
      *(uint64_t *)&hello[0] = *(uint64_t *)"Hello, ";
      *(uint64_t *)&hello[7] = *(uint64_t *)"World!!";
   }
   return self;
}

- (void)sayHello
{
   puts(hello);
}

@end

int main(int argc, const char *argv[])
{
   Hello *hey = [Hello new];
   [hey sayHello];
   [hey release];
   return 0;
}
Code:
# clang -g -O0 -std=c11 BareClass.m hello.m -I/usr/local/include -L/usr/local/lib -lobjc -o hello
# ./hello
Hello, World!!
# lldb -- hello
(lldb) breakpoint set -f hello.m -l 35
(lldb) run
(lldb) gui
3447
 

Attachments

  • lldb-gui-hello.png
    lldb-gui-hello.png
    40.1 KB · Views: 961
Last edited:
Top