Object oriented framework for C.
Zlib license.
About
Objectively is a cross-platform object oriented framework for the C programming language. Objectively provides rich OO semantics to enable object oriented programming directly in C.
Features
- Windows, macOS, iOS, Android & Linux cross-platform support
- Single-parent inheritance with starts-with struct composition
- Class and instance methods with strongly typed interfaces
- Automatic class loading and lifecycle management
- Automatic memory management with reference counting
- Unicode strings with multibyte character set support
- Collections for Objects and C types: Array, Dictionary, List, Set and more
- JSON parsing, marshaling, and JSONPath queries
- Concurrency: Lock, Condition, Thread, Operation, OperationQueue
- Networking: URLSession, JSONContext & RESTClient
Class Hierarchy
Browse the class hierarchy to navigate the full API.
Declaring a Type
Every Objectively type consists of three components:
1. The instance struct — starts with the parent type, then the interface pointer, then instance variables:
struct Hello {
HelloInterface *interface;
const char *greeting;
};
Object is the root Class of The Objectively Class hierarchy.
2. The interface struct — starts with the parent interface, then method function pointers:
struct HelloInterface {
ObjectInterface objectInterface;
Hello *(*helloWithGreeting)(const char *greeting);
Hello *(*initWithGreeting)(Hello *self, const char *greeting);
void (*sayHello)(const Hello *self);
};
3. The Class archetype — a single exported function that returns the Class:
#define OBJECTIVELY_EXPORT
The runtime representation of a Class.
Implementing a Type
#include <stdio.h>
#define _Class _Hello
static Hello *helloWithGreeting(const char *greeting) {
return $(
alloc(Hello), initWithGreeting, greeting);
}
static Hello *initWithGreeting(Hello *self, const char *greeting) {
if (self) {
self->greeting = greeting ?: "Hello World!";
}
return self;
}
static void sayHello(const Hello *self) {
printf("%s\n", self->greeting);
}
((HelloInterface *) clazz->
interface)->helloWithGreeting = helloWithGreeting;
((HelloInterface *) clazz->
interface)->initWithGreeting = initWithGreeting;
((HelloInterface *) clazz->
interface)->sayHello = sayHello;
}
.name = "Hello",
.instanceSize = sizeof(Hello),
.interfaceOffset = offsetof(Hello, interface),
.interfaceSize = sizeof(HelloInterface),
});
});
return clazz;
}
#undef _Class
static void initialize(Class *clazz)
static Array * init(Array *self)
Class * _initialize(const ClassDef *def)
Initializes the given Class.
#define alloc(type)
Allocate and initialize and instance of type.
#define super(type, obj, method,...)
Objectively: Ultra-lightweight object oriented framework for GNU C.
#define do_once(once, block)
Executes the given block at most one time.
ClassDefs are passed to _initialize via an archetype to initialize a Class.
ident interface
The interface of the Class.
Using a Type
Using your custom type is trivial. Instantiate it like you would any Objectively type.
Hello *hello = $(
alloc(Hello), initWithGreeting,
"Hello, World!");
$(hello, sayHello);
ident release(ident obj)
Atomically decrement the given Object's reference count. If the resulting reference count is 0,...
See Hello.h and Hello.c for the full source.
Initialization
There is no explicit setup or teardown with Objectively. To instantiate a type, simply call alloc from anywhere in your program. The first time a type is instantiated, its Class initializer, initialize, is called. Use initialize to setup your interface, override methods, or initialize a library your class wraps. When your application terminates, an optional Class destructor, destroy, is also called.
Invoking an instance method
To invoke an instance method, use the $ macro.
static bool waitUntilDate(Condition *self, const Date *date)
Invoking a Class method
To invoke a Class method, use the $$ macro.
static Dictionary * dictionary(void)
Overriding a method
To override a method, overwrite the function pointer from within your Class' initialize method.
static bool isEqual(const Object *self, const Object *other)
static void dealloc(Object *self)
Calling super
To invoke a supertype's method implementation, use the super macro.
Managing memory
Objectively uses reference counting to govern object retention. Newly instantiated Objects have a reference count of 1. To retain a strong reference to an Object, call retain(obj). To relinquish it, call release(obj). Once an Object's reference count reaches 0, it is deallocated. Remember to balance every retain with a release.
Shared instances
A shared instance or singleton pattern can be achieved through Class methods and release-on-destroy.
});
}
}
static void destroy(Class *clazz)
static Log * _sharedInstance
static Log * sharedInstance(void)
A management context for loading resources via URLs.
Remember to wire up the desctructor in your Class' initialization block. See Once.h for details on do_once.