Objective-C
| Company type | Programming language |
|---|---|
| Industry | Software development |
| Founded | January 1, 1980 |
| Founder | Brad Cox, Tom Love |
Objective-C is a versatile, high-level programming language that incorporates object-oriented principles and Smalltalk-style message passing into the C language. Conceived by Brad Cox and Tom Love during the early 1980s, it was selected by NeXT as the primary language for their NeXTSTEP operating system. After Apple acquired NeXT in 1997, Objective-C became the dominant language for creating macOS and iOS applications through the Cocoa and Cocoa Touch frameworks until Swift emerged in 2014.
For projects aimed at platforms outside of Apple’s ecosystem or those not reliant on Apple APIs, Objective-C code can be compiled using GNU GCC or LLVM/Clang compilers. Source code files generally have the extension for implementation files and for header files, while Objective-C++ files are identified with .
History
The inception of Objective-C is credited mainly to Brad Cox and Tom Love during their tenure at Productivity Products International (PPI) in the early 1980s.
Prior to establishing PPI, both developers encountered Smalltalk at ITT Corporation’s Programming Technology Center in 1981, marking the beginning of Objective-C’s development. Cox emphasized software reuse and acknowledged Smalltalk’s advantages for system programmers but recognized the necessity of maintaining compatibility with C—an essential requirement within ITT’s telecommunications domain.
To integrate Smalltalk features, Cox devised a C preprocessor named Object-Oriented Pre-Compiler (OOPC), which extended C with object-oriented capabilities. Meanwhile, Love, who joined Schlumberger Research in 1982, acquired one of the earliest commercial Smalltalk-80 versions, influencing their ongoing work.
To validate their approach, Cox demonstrated that achieving interchangeable software components required only practical modifications to tools: adaptable object support, accessible libraries, and packaging code into a platform-independent format.
Together, Love and Cox launched PPI to bring Objective-C to market by combining a compiler with accompanying class libraries. In 1986, Cox authored Object-Oriented Programming, An Evolutionary Approach, which outlined Objective-C’s foundational design. Although broader issues of software reuse were acknowledged, Objective-C was often evaluated through direct feature comparisons with other languages.
Growth via NeXT
In 1988, NeXT obtained a license for Objective-C from StepStone (previously PPI) and enhanced the GCC compiler to accommodate it. NeXT also developed the Application Kit (AppKit) and Foundation Kit libraries, which became core components of the NeXTSTEP user interface and its Interface Builder tool. Despite limited commercial success of NeXT hardware, their software offerings earned significant industry acclaim. Eventually, NeXT discontinued hardware manufacturing to concentrate on marketing NeXTSTEP (and later OPENSTEP) as a platform for bespoke software development.
To adhere to the GPL, NeXT initially intended to distribute the Objective-C frontend separately so users could link it with GCC themselves. However, following legal consultation, this plan was abandoned in favor of integrating Objective-C directly into GCC under GPL licensing.
Steve Naroff, transitioning from StepStone to NeXT, spearheaded development of GCC extensions supporting Objective-C. While these compiler modifications were released under GPL, runtime libraries remained proprietary, restricting open source adoption. This limitation motivated others to create open source runtime alternatives. Naroff subsequently contributed to Apple’s Objective-C frontend for Clang.
The GNU project developed a free software implementation of Cocoa, known as GNUstep, based on the OpenStep specification. Dennis Glatting authored the initial GNU Objective-C runtime in 1992; since 1993, Kresten Krab Thorup—also affiliated with NeXT—has maintained the runtime used today.
Apple's evolution and Swift introduction
Following Apple's acquisition of NeXT in 1996, the company incorporated OpenStep into its new operating system, Mac OS X. This integration brought in Objective-C, NeXT’s developer environment based on Objective-C, including tools like Project Builder and Interface Builder, which were eventually consolidated into Xcode. The foundation of Apple's current Cocoa API primarily originates from OpenStep interface components and continues to serve as the main Objective-C development framework.
At the 2014 WWDC event, Apple unveiled the Swift programming language, which was characterized as "Objective-C without the C."
Syntax
Objective-C functions as a lightweight extension over the C language, being a strict superset of C. This means any valid C program can be compiled with an Objective-C compiler, and C code can be embedded within Objective-C classes.
The object-oriented syntax in Objective-C is inspired by Smalltalk, whereas its non-object-oriented elements—including primitive data types, preprocessing directives, expressions, and function declarations—align closely with C. Its object-oriented capabilities implement message passing akin to Smalltalk.
Message passing
Unlike C++’s Simula-based model that relies on compile-time method binding, Objective-C’s object-oriented paradigm is centered around message passing to objects. Messages are dynamically resolved at runtime by the receiving object. Each method corresponds to a unique identifier known as a selector (), typically represented as a string ending with a colon, which maps internally to a C function pointer (). This dynamic resolution implies no type checking occurs during compilation; if an object cannot respond to a message, an exception is triggered.
In C++, invoking a method on an object pointer appears as follows:
<syntaxhighlight lang="cpp">obj->method(argument);</syntaxhighlight>
The equivalent Objective-C syntax is:
<syntaxhighlight lang="objc">[obj method:argument];</syntaxhighlight>
The compiler converts this syntax into calls to the objc_msgSend runtime function family. While GNU implementations previously used objc_msg_lookup (now deprecated), objc_msgSend remains standard.
Simula-style OOP (as in C++) offers benefits such as multiple inheritance and faster execution due to compile-time binding but lacks inherent support for dynamic dispatch and mandates implementations for all methods unless abstract. Objective-C’s Smalltalk-inspired message passing promotes dynamic binding, allowing messages to be sent to collections where only certain objects respond without causing runtime errors. This approach facilitates method resolution without requiring compile-time knowledge of the object's class, enhancing flexibility for dynamic typing and late binding scenarios.
Class interfaces and implementations
Objective-C distinguishes between a class’s interface and its implementation by separating them into different sections of code—commonly placing the interface in a header (.h) file and the implementation in a source (.m) file. Header files resemble those used in C, while implementation files are akin to C source files.
Interface
The interface specifies a class’s structure similarly to class declarations in languages like C++ or Python. Typically, the header file bears the same name as the class it defines, for example, for the class.
A sample interface declaration might look like this: <syntaxhighlight lang="objc"> @interface ClassName : SuperclassName {
// instance variables
} + classMethod1; + (return_type)classMethod2; + (return_type)classMethod3:(param1_type)param1_varName;
- (return_type)instanceMethod1With1Parameter:(param1_type)param1_varName; - (return_type)instanceMethod2With2Parameters:(param1_type)param1_varName
param2_callName:(param2_type)param2_varName;
@end </syntaxhighlight>
Here, methods prefixed with plus signs represent class methods that can be invoked on the class itself, whereas those with minus signs denote instance methods callable on individual instances. Class methods lack access to instance variables.
This structure roughly parallels the following interface in C++: <syntaxhighlight lang="cpp"> class ClassName : public SuperclassName { protected:
// instance variables
public:
// Static (class) functions static void *classMethod1(); static return_type classMethod2(); static return_type classMethod3(param1_type param1_varName);
// Member (instance) functions
return_type instanceMethod1With1Parameter(param1_type param1_varName);
return_type
instanceMethod2With2Parameters(param1_type param1_varName,
param2_type param2_varName = default);
}; </syntaxhighlight>
It is important to note that Objective-C’s method naming convention interleaving selector segments with arguments (e.g., ) has no direct counterpart in C or C++.
Return types may include standard C types, pointers to generic Objective-C objects (id), specific classes such as NSArray *, NSImage *, NSString *, or the class type itself (instancetype). If unspecified, id is assumed by default.
Method parameters start with a label that forms part of the method name followed by a colon, then the argument type enclosed in parentheses and finally the parameter name. Labels can be omitted when desired: <syntaxhighlight lang="objc"> - (void)setRangeStart:(int)start end:(int)end; - (void)importDocumentWithName:(NSString *)name
withSpecifiedPreferences:(Preferences *)prefs
beforePage:(int)insertPage;
</syntaxhighlight>
An extension of interfaces is known as a category, which allows developers to add new methods to existing classes without subclassing.
Implementation
The interface specifies the class's method signatures without including their actual code; the concrete implementations are found in files with the .m suffix, which originally stood for "messages."
<syntaxhighlight lang="objc"> @implementation classname + (return_type)classMethod {
// method body
} - (return_type)instanceMethod {
// method body
} @end </syntaxhighlight>
Methods correspond to their declared interfaces. Objective-C syntax supports pseudo-named arguments as follows:
<syntaxhighlight lang="objc"> - (void)changeColorToRed:(float)red green:(float)green blue:(float)blue {
//... Method body ...
}
// Invoked like this: [myColor changeColorToRed:5.0 green:2.0 blue:6.0]; </syntaxhighlight>
Internally, method selectors encode both the class and parameter names, for example, a selector might be represented as . These internal identifiers are seldom accessed directly; instead, messages are translated into runtime function invocations, where the receiver's class is typically determined dynamically during execution.
Instantiation
Creating Objective-C objects involves first allocating memory and then initializing it, commonly combined in a single statement to ensure the object is properly set up:
<syntaxhighlight lang="objc">MyObject *foo = [[MyObject alloc] init];</syntaxhighlight>
Custom initialization methods enable instantiation with parameters:
<syntaxhighlight lang="objc">MyObject *foo = [[MyObject alloc] initWithString:myString];</syntaxhighlight>
Alternatively, the new method performs allocation and default initialization in one step:
<syntaxhighlight lang="objc">MyObject *foo = [MyObject new];</syntaxhighlight>
Certain classes offer class-level initializer methods that return autoreleased objects and may accept arguments:
<syntaxhighlight lang="objc"> MyObject *foo = [MyObject object]; MyObject *bar = [MyObject objectWithString:@"Wikipedia :)"]; </syntaxhighlight>
The alloc message reserves space for instance variables and zeroes them out, thereby creating an instance of the class. The init message completes setup, often following this structure:
<syntaxhighlight lang="objc" line> - (id)init {
self = [super init];
if (self) {
// perform setup here
}
return self;
} </syntaxhighlight>
The return type represents a pointer to any object. This approach guarantees that superclass initialization occurs before subclass-specific configuration. If returns , initialization is aborted to avoid incomplete objects. On failure, cleanup includes releasing self and returning . When multiple initializers exist, only the designated initializer invokes the superclass; other initializers delegate to it.
Protocols
Objective-C, developed at NeXT, introduced the concept of multiple inheritance limited to specifications (not implementations) through protocols, which are analogous to abstract base classes in C++, or interfaces in Java and C#. It supports both informal ad hoc protocols and compiler-enforced formal protocols.
Informal protocols define optional methods that a class can implement; these are documented but not enforced by the compiler and are implemented as a category on NSObject. For instance, a text field delegate might optionally implement an auto-completion method detected via reflection.
Formal protocols function similarly to interfaces in Java or C#. Classes that declare adherence must implement all required methods; before Objective-C 2.0, all protocol methods were mandatory, but later versions permit optional methods. Protocol conformance is declared within the class interface and can be verified at runtime. Protocols do not provide implementations but ensure that specified methods exist. They are extensively utilized in NeXT/Apple's Distributed Objects framework to describe remote object capabilities.
Example declaration syntax:
<syntaxhighlight lang="objc"> @protocol NSLocking - (void)lock; - (void)unlock; @end </syntaxhighlight>
Declaring that a class conforms:
<syntaxhighlight lang="objc"> @interface NSLock : NSObject <NSLocking> // ... @end </syntaxhighlight>
indicates that instances of NSLock implement the locking protocol methods.
Dynamic typing
Objective-C incorporates dynamic typing, which permits sending messages to objects without requiring explicit interface declarations. This feature offers adaptability through mechanisms such as message forwarding or delegation, where messages not recognized by an object can be redirected to alternative objects or managed by error handling routines. If a message is neither handled nor forwarded, a runtime exception is triggered. Messages directed at nil are either quietly ignored or may cause generic exceptions depending on the compiler configuration.
Static typing can be optionally applied to variables, allowing for compile-time type verification and minimizing runtime errors. Illustrations include:
<syntaxhighlight lang="objc"> - (void)setMyValue:(id)foo; </syntaxhighlight> Accepts any instance of a class.
<syntaxhighlight lang="objc"> - (void)setMyValue:(id<NSCopying>)foo; </syntaxhighlight> Requires the object to conform to the NSCopying protocol.
<syntaxhighlight lang="objc"> - (void)setMyValue:(NSNumber *)foo; </syntaxhighlight> Demands an instance of NSNumber.
<syntaxhighlight lang="objc"> - (void)setMyValue:(NSNumber<NSCopying> *)foo; </syntaxhighlight> Requires an NSNumber object that also conforms to NSCopying.
All Objective-C objects are represented as pointers; static initialization is not permitted. The fundamental type points to an object containing only an isa pointer, which identifies its class. Unlike C++, C types such as structs remain distinct and separate from the Objective-C object system.
Forwarding
Objective-C enables sending messages to objects that might not have a direct response implementation. Rather than ignoring or handling the message internally, an object can delegate the message to another object capable of responding. This forwarding capability streamlines the implementation of design patterns like the observer pattern and proxy pattern.
The Objective-C runtime specifies two categories of methods within :
- Forwarding methods:<syntaxhighlight lang="objc">
- (retval_t)forward:(SEL)sel args:(arglist_t)args; // GCC - (id)forward:(SEL)sel args:(marg_list)args; // NeXT/Apple</syntaxhighlight>
- Action methods:<syntaxhighlight lang="objc">
- (retval_t)performv:(SEL)sel args:(arglist_t)args; // GCC - (id)performv:(SEL)sel args:(marg_list)args; // NeXT/Apple</syntaxhighlight>
To enable forwarding, one overrides the forwarding method to specify custom behavior. The action method usually remains intact since it executes a selector with supplied arguments. In Objective-C, the SEL type denotes message selectors.
Within frameworks such as OpenStep, Cocoa, and GNUstep, message forwarding is implemented using the method rather than .
Example
An elementary example illustrating message forwarding through delegation:
- Forwarder.h
<syntaxhighlight lang="objc">
- import <objc/Object.h>
@interface Forwarder : Object {
id recipient; // Object designated to receive forwarded messages.
}
- (id)recipient; - (id)setRecipient:(id)_recipient; @end </syntaxhighlight>
- Forwarder.m
<syntaxhighlight lang="objc">
- import "Forwarder.h"
@implementation Forwarder - (retval_t)forward:(SEL)sel args:(arglist_t)args {
if ([recipient respondsToSelector:sel]) {
return [recipient performv:sel args:args];
} else {
return [self error:"Recipient does not respond"];
}
}
- (id)setRecipient:(id)_recipient {
[recipient autorelease]; recipient = [_recipient retain]; return self;
}
- (id)recipient {
return recipient;
} @end </syntaxhighlight>
- Recipient.h
<syntaxhighlight lang="objc">
- import <objc/Object.h>
@interface Recipient : Object - (id)hello; @end </syntaxhighlight>
- Recipient.m
<syntaxhighlight lang="objc">
- import "Recipient.h"
@implementation Recipient
- (id)hello {
printf("Recipient says hello!\n");
return self;
}
@end </syntaxhighlight>
- main.m
<syntaxhighlight lang="objc">
- import "Forwarder.h"
- import "Recipient.h"
int main(void) {
Forwarder *forwarder = [Forwarder new]; Recipient *recipient = [Recipient new];
[forwarder setRecipient:recipient]; // Set the recipient. [forwarder hello]; // Message delegated to recipient.
[recipient release]; [forwarder release];
return 0;
} </syntaxhighlight>
Notes
When using the gcc to compile, a warning message appears:
This alert indicates that does not handle hello messages. However, it can be disregarded safely in this context because message forwarding is implemented. Executing the program produces the following output:
Categories
Objective-C was designed with a focus on maintainability for extensive codebases by dividing code into smaller, manageable segments. It expanded on Smalltalk’s categories concept to facilitate modular organization of code.
Categories permit adding methods to a class during run-time, enabling developers to enhance or alter existing classes without needing recompilation or access to the original source code. For instance, a spell-check feature could be appended externally to a String class.
Methods introduced via categories are indistinguishable from those originally declared in the class and possess full access to instance variables, including private ones. If a category method shares the same signature as an existing method, it replaces the original, allowing for bug corrections or global behavior modifications. Nevertheless, when multiple categories define identically named methods with differing signatures, which one takes precedence is unpredictable.
Comparable mechanisms exist in other programming languages: TOM builds upon Objective-C’s model by permitting variable additions; C# and Visual Basic (.NET) implement extension methods but do not have access to private variables. In dynamic languages such as Ruby, this practice is known as "monkey patching."
Logtalk treats categories as first-class constructs that enable precise composition and can be imported by various classes and prototypes, offering more modularity than Objective-C’s approach.
Example use of categories
The following example constructs an class by initially defining a fundamental class with accessor methods, then enhancing it by adding two categories, and , respectively. Although categories can reach private data members of the base class, it is advisable to interact through accessor methods to preserve encapsulation. Categories generally add new methods but are discouraged from overriding subclass behavior (monkey patching). Informal protocols are implemented as a category on the base class. Files containing categories follow the naming pattern BaseClass+ExtensionClass.h.
- Integer.h
- <syntaxhighlight lang="objc">
- import <objc/Object.h>
@interface Integer : Object {
int integer;
}
- (int)integer; - (id)integer:(int)_integer; @end </syntaxhighlight>
- Integer.m
- <syntaxhighlight lang="objc">
- import "Integer.h"
@implementation Integer - (int) integer {
return integer;
}
- (id) integer: (int) _integer {
integer = _integer; return self;
} @end </syntaxhighlight>
- Integer+Arithmetic.h
- <syntaxhighlight lang="objc">
- import "Integer.h"
@interface Integer (Arithmetic) - (id) add: (Integer *) addend; - (id) sub: (Integer *) subtrahend; @end </syntaxhighlight>
- Integer+Arithmetic.m
- <syntaxhighlight lang="objc">
- import "Integer+Arithmetic.h"
@implementation Integer (Arithmetic) - (id) add: (Integer *) addend {
return [self integer: [self integer] + [addend integer]];
}
- (id) sub: (Integer *) subtrahend {
return [self integer: [self integer] - [subtrahend integer]];
} @end </syntaxhighlight>
- Integer+Display.h
- <syntaxhighlight lang="objc">
- import "Integer.h"
@interface Integer (Display) - (id) showstars; - (id) showint; @end </syntaxhighlight>
- Integer+Display.m
- <syntaxhighlight lang="objc">
- import "Integer+Display.h"
@implementation Integer (Display) - (id) showstars {
int i, x = [self integer];
for (i = 0; i < x; i++) {
printf("*");
}
printf("\n");
return self;
}
- (id) showint {
printf("%d\n", [self integer]);
return self;
} @end </syntaxhighlight>
- main.m
- <syntaxhighlight lang="objc" line>
- import "Integer.h"
- import "Integer+Arithmetic.h"
- import "Integer+Display.h"
int main(void) {
Integer *num1 = [Integer new], *num2 = [Integer new]; int x;
printf("Enter an integer: ");
scanf("%d", &x);
[num1 integer:x]; [num1 showstars];
printf("Enter an integer: ");
scanf("%d", &x);
[num2 integer:x]; [num2 showstars];
[num1 add:num2]; [num1 showint];
return 0;
} </syntaxhighlight>
Notes
Example of compilation:
If the and associated code are excluded, the application continues to function, permitting selective compilation of categories depending on the required features.
Posing
In Objective-C, one class can completely substitute another within a program, a mechanism known as "posing." This capability was deprecated starting with Mac OS X v10.5 and is not supported in the 64-bit runtime environment. Comparable results can be achieved through method swizzling within categories, which exchanges implementations of methods sharing identical signatures.
When posing is available, all messages directed to the original class are handled by the posing class, subject to these conditions:
- The posing class must be a direct or indirect subclass of the class it replaces.
- It cannot introduce new instance variables absent from the original class but may override existing methods.
- The original class must not have received any messages before posing occurs.
Posing, akin to categories, permits global extension of existing classes but offers two additional benefits:
- The posing class can invoke overridden methods via super, thereby including the original class's behavior.
- It has the ability to override methods defined in categories.
Illustration:
<syntaxhighlight lang="objc"> @interface CustomNSApplication : NSApplication @end
@implementation CustomNSApplication - (void) setMainMenu: (NSMenu*) menu {
// customize menu processing
} @end
class_poseAs ([CustomNSApplication class], [NSApplication class]); </syntaxhighlight>
This approach intercepts every call to setMainMenu on NSApplication.
#import
The Objective-C directive #import ensures a file’s contents are included only once per compilation unit, removing the necessity for include guards. It is distinct from the C++ keyword import, introduced for modules in C++20, and from MSVC’s proprietary #import used for importing type libraries.
Linux gcc compilation
<syntaxhighlight lang="objc"> // FILE: hello.m
- import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSLog(@"Hello, World! \n"); return 0;
} </syntaxhighlight>
<syntaxhighlight lang="shell-session"> $ gcc \
$(gnustep-config --objc-flags) \ -o hello \ hello.m \ -L /GNUstep/System/Library/Libraries \ -lobjc \ -lgnustep-base
$ ./hello </syntaxhighlight>
Other features
Objective-C provides versatile mechanisms for addressing various programming needs:
- Delegation and remote invocation can be implemented straightforwardly using categories combined with message forwarding.
- Modifying the isa pointer at runtime enables dynamic class changes. This method has been used for debugging purposes by turning deallocated objects into zombies that flag erroneous accesses. It was also utilized in Enterprise Objects Framework to handle database faults. Presently, Apple’s Foundation Framework applies swizzling to support Key-Value Observing.
Objective-C++
Objective-C++ is a language variant supported by both the GNU Compiler Collection and Clang front-ends, allowing source files containing a mixture of C++ and Objective-C syntax to be compiled. Although previously mentioned in Apple documentation, references have since been removed.
Objective-C++ combines C++ with Objective-C features but enforces several constraints:
- A C++ class cannot inherit from an Objective-C class, nor can an Objective-C class inherit from a C++ class.
- C++ namespaces are not permitted inside Objective-C declarations; such declarations must reside at global scope only.
- Objective-C classes cannot include instance variables of C++ classes that lack a default constructor or contain virtual methods; however, pointers to C++ objects are allowed without restriction.
- The "by value" semantics typical of C++ do not apply to Objective-C objects, which are always accessed via pointers.
- Objective-C declarations cannot appear within C++ template definitions, although Objective-C types may be used as template parameters in C++.
- Exception handling is separate between Objective-C and C++; exception handlers cannot catch exceptions thrown by the other language, potentially preventing destructors from running. Newer Objective-C 2.0 runtimes address this by replacing or integrating exceptions with those from C++.
- While Objective-C blocks differ from C++11 lambdas, on macOS lambdas passed where blocks are expected are automatically converted behind the scenes.
Objective-C 2.0
During the 2006 Worldwide Developers Conference, Apple unveiled "Objective-C 2.0," an enhanced iteration of the language that incorporated modern garbage collection, improved syntax, optimized runtime performance, and support for 64-bit architectures. The Objective-C 2.0 compiler was integrated into Mac OS X v10.5, which launched in October 2007. Additionally, GCC 4.6 introduced compatibility with numerous Objective-C advancements, including declared and synthesized properties, dot syntax, fast enumeration, optional protocol methods, class extensions, and an updated GNU Objective-C runtime API.
The label Objective-C 2.0 represented a shift from earlier versioning conventions; the final Objective-C release for NeXT was identified as "objc4," a designation preserved in the legacy runtime source code for Mac OS X Leopard (10.5).
Garbage collection
Objective-C 2.0 brought in an optional conservative, generational garbage collector that transformed reference counting calls like "retain" and "release" into no-operations when activated. All objects were eligible for garbage collection, and C pointers marked with "__strong" were managed through compiler-inserted write-barriers. A zeroing weak mechanism ensured that "__weak" pointers were reset to nil upon object deallocation. This garbage collection system was not supported on iOS platforms.
The garbage collector functioned on a low-priority background thread to maintain application responsiveness but was deprecated starting with Mac OS X v10.8 in favor of Automatic Reference Counting (ARC). On iOS 7 devices utilizing ARM64, Objective-C employs tagged pointers using 19 bits within a 64-bit word to optimize reference counting and memory handling.
Properties
Objective-C 2.0 introduced a new syntax for declaring instance variables as properties, allowing developers to specify attributes that control the automatic generation of accessor methods. Properties serve as publicly accessible instance variables with controlled access options (such as read-only). They can be defined with the readonly attribute and storage qualifiers like assign, copy, or retain. By default, properties are atomic, ensuring thread safety through locking mechanisms; however, marking them as nonatomic disables this locking behavior.
<syntaxhighlight lang="objc"> @interface Person : NSObject { @public
NSString *name;
@private
int age;
}
@property(copy) NSString *name; @property(readonly) int age;
- (id)initWithAge:(int)age; @end </syntaxhighlight>
Properties are typically implemented using the @synthesize directive, which auto-generates getter and setter methods unless these are explicitly defined or the property is declared with @dynamic. Since clang version 3.1, any property not marked as @dynamic, readonly, or fully implemented is automatically synthesized.
<syntaxhighlight lang="objc"> @implementation Person @synthesize name;
- (id)initWithAge:(int)initAge {
self = [super init];
if (self) {
age = initAge; // direct ivar assignment
}
return self;
}
- (int)age {
return age;
} @end </syntaxhighlight>
Access to properties is possible through message passing, dot syntax, or Key-Value Coding methods such as "valueForKey:" and "setValue:forKey:".
<syntaxhighlight lang="objc"> Person *aPerson = [[Person alloc] initWithAge:53]; aPerson.name = @"Steve"; // dot syntax invokes synthesized setter NSLog(@"Access via message (%@), dot notation (%@), KVC (%@), direct ivar (%@)",
[aPerson name], aPerson.name, [aPerson valueForKey:@"name"], aPerson->name);
</syntaxhighlight>
Inside instance methods, dot notation should be used with the keyword:
<syntaxhighlight lang="objc"> - (void)introduceMyselfWithProperties:(BOOL)useGetter {
NSLog(@"Hi, my name is %@.", (useGetter ? self.name : name));
} </syntaxhighlight>
Classes and protocols can dynamically inspect their declared properties:
<syntaxhighlight lang="objc"> int propertyCount = 0; objc_property_t *propertyList = class_copyPropertyList([aPerson class], &propertyCount);
for (int i = 0; i < propertyCount; i++) {
objc_property_t thisProperty = propertyList[i]; const char *propertyName = property_getName(thisProperty); NSLog(@"Person declares a property: '%s'", propertyName);
} </syntaxhighlight>
Non-fragile instance variables
Objective-C 2.0 introduces support for non-fragile instance variables on runtimes such as 64-bit macOS and all iOS versions. This feature incorporates an additional indirection layer when accessing instance variables, allowing the dynamic linker to modify instance layouts during runtime. The principal business benefits include:
- Resolving the fragile binary interface issue by permitting superclass size modifications without breaking binary compatibility.
- Allowing the runtime synthesis of property-backed instance variables without the need for explicit declarations in the class interface.
Fast enumeration
With Objective-C 2.0, a fast enumeration syntax is provided, enabling more efficient traversal of collections compared to traditional NSEnumerator or index-based looping techniques. Instead of invoking methods, fast enumeration uses pointer arithmetic through the NSFastEnumeration protocol, resulting in enhanced execution speed.
Class extensions
Class extensions share the same syntax as categories but omit the category name, enabling direct addition of methods and properties to the original class. This mechanism keeps these methods private and ensures compiler checks for their implementation, thereby improving code robustness while keeping internal details hidden from public headers.
Implications for Cocoa development
Applications utilizing Objective-C 2.0 enhancements are not compatible with macOS versions earlier than 10.5 (Leopard). Features such as fast enumeration generate binaries that will cause crashes on Mac OS X 10.4 or older systems.
Blocks
Blocks represent a nonstandard extension applicable to Objective-C, C, and C++ that facilitates closure creation using specialized syntax. This feature is supported starting from Mac OS X 10.6 "Snow Leopard," iOS 4 and later, as well as GNUstep with libobjc2 version 1.7 compiled with clang 3.1 or newer.
<syntaxhighlight lang="objc">
- include <stdio.h>
- include <Block.h>
typedef int (^IntBlock)();
IntBlock MakeCounter(int start, int increment) {
__block int i = start;
return Block_copy( ^ {
int ret = i;
i += increment;
return ret;
});
}
int main(void) {
IntBlock mycounter = MakeCounter(5, 2);
printf("First call: %d\n", mycounter());
printf("Second call: %d\n", mycounter());
printf("Third call: %d\n", mycounter());
Block_release(mycounter);
return 0;
} /* Output:
First call: 5 Second call: 7 Third call: 9
- /
</syntaxhighlight>
Modern Objective-C
Apple has expanded upon Objective-C 2.0 capabilities through its LLVM-based clang compiler, featuring Apple-specific versioning that differs from the open-source LLVM releases; refer to for detailed version correspondence.
Automatic Reference Counting
Automatic Reference Counting (ARC) is a compile-time mechanism that automates memory management by removing the need for manual retain and release calls. Unlike garbage collection performed at runtime, ARC integrates reference count handling directly into the compilation process, minimizing overhead. It supports coexistence with manual memory management since ARC can be selectively disabled on individual source files within ARC-enabled projects. Xcode also provides tools for automatic migration of projects to ARC.
Introduced with LLVM version 3.0 (included in Xcode 4.2 and Apple LLVM compiler 3.0), ARC has greatly simplified memory management in Objective-C, improving both developer efficiency and application reliability.
Literals
The NeXT and Apple Objective-C runtimes have historically supported a concise syntax for string creation using @"a new string", alongside CoreFoundation constants such as kCFBooleanTrue and kCFBooleanFalse to represent Boolean NSNumber values. This approach streamlines code by eliminating the need for longer initializers like initWithString:.
With the introduction of Apple’s LLVM compiler version 4.0 (Xcode 4.4), literal syntax was expanded to include arrays, dictionaries, and numeric types (NSArray, NSDictionary, NSNumber). This compiler release aligns with open source LLVM and Clang 3.1.
Example demonstrating code without literals:
<syntaxhighlight lang="objc"> NSArray *myArray = [NSArray arrayWithObjects:object1, object2, object3, nil]; NSDictionary *myDictionary1 = [NSDictionary dictionaryWithObject:someObject forKey:@"key"]; NSDictionary *myDictionary2 = [NSDictionary dictionaryWithObjectsAndKeys:object1, key1, object2, key2, nil]; NSNumber *myNumber = [NSNumber numberWithInt:myInt]; NSNumber *mySumNumber = [NSNumber numberWithInt:(2 + 3)]; NSNumber *myBoolNumber = [NSNumber numberWithBool:YES]; </syntaxhighlight>
Equivalent example utilizing literals:
<syntaxhighlight lang="objc"> NSArray *myArray = @[ object1, object2, object3 ]; NSDictionary *myDictionary1 = @{ @"key" : someObject }; NSDictionary *myDictionary2 = @{ key1 : object1, key2 : object2 }; NSNumber *myNumber = @(myInt); NSNumber *mySumNumber = @(2 + 3); NSNumber *myBoolNumber = @YES; NSNumber *myIntegerNumber = @8; </syntaxhighlight>
Prior to Xcode 13, literals for arrays, dictionaries, and numbers compiled into method invocations that generated autoreleased objects under manual reference counting (MRC), necessitating careful handling when used with global or static variables.
Starting with Xcode 13 (clang 13.0.0), these literals are embedded directly into the binary at compile time similarly to string literals. This enhancement improves both runtime efficiency and memory usage on Apple platforms. The feature is enabled by default but can be controlled through compiler options such as -fno-objc-constant-literals.
Subscripting
Beginning with Apple’s LLVM compiler version 4.0 and later, subscripting support was added to arrays and dictionaries (NSArray and NSDictionary). This allows elements to be accessed or modified using bracket notation [ ], simplifying element retrieval by index (arrays) or key (dictionaries).
Example without subscripting:
<syntaxhighlight lang="objc"> id object1 = [someArray objectAtIndex:0]; id object2 = [someDictionary objectForKey:@"key"]; [someMutableArray replaceObjectAtIndex:0 withObject:object3]; [someMutableDictionary setObject:object4 forKey:@"key"]; </syntaxhighlight>
Example applying subscripting:
<syntaxhighlight lang="objc"> id object1 = someArray[0]; id object2 = someDictionary[@"key"]; someMutableArray[0] = object3; someMutableDictionary[@"key"] = object4; </syntaxhighlight>
"Modern" Objective-C Syntax (1997)
Following Apple’s acquisition of NeXT, an alternative "Modern Syntax" was introduced targeting developers familiar with Java. This syntax presented different styles for method invocation and declaration without altering underlying functionality. For instance:
<syntaxhighlight lang="objc">
object = [[MyClass alloc] init]; [object firstLabel:param1 secondLabel:param2];
</syntaxhighlight>
was transformed into
<syntaxhighlight lang="objc">
object = (MyClass.alloc).init; object.labels(param1, param2);
</syntaxhighlight>
Similarly, method declarations shifted from
<syntaxhighlight lang="objc">
-(void) firstLabel:(int)param1 secondLabel:(int)param2;
</syntaxhighlight>
to
<syntaxhighlight lang="objc">
-(void) labels(int param1, int param2);
</syntaxhighlight>
This modern syntax variant is no longer supported in contemporary Objective-C versions.
mulle-objc
The mulle-objc initiative represents a unique reimplementation of Objective-C that supports both GCC and Clang/LLVM compilers. It features distinct syntax, semantics, and ABI compatibility, targeting operating systems such as Linux, FreeBSD, and Windows.
Portable Object Compiler
Besides the GCC/NeXT/Apple implementations, the open-source Portable Object Compiler (POC) provides an alternative Objective-C variant. POC introduces a different set of language extensions—like Smalltalk-style blocks—but does not include protocols or categories found in OpenStep-based versions. It corresponds to an earlier iteration of Objective-C that aligns with Brad Cox's 1991 specifications.
The runtime library for POC, named ObjectPak, is derived from Cox’s original ICPak101 library and stands apart from the OpenStep FoundationKit.
GEOS Objective-C
The PC GEOS platform utilized a language called GEOS Objective-C or goc. Despite its name, it shares only conceptual similarities and the use of @-prefixed keywords with conventional Objective-C.
Clang
The Clang compiler collection, a component of the LLVM project, supports Objective-C alongside other programming languages. Following GCC 4.3’s (2008) transition to GPLv3 licensing, Apple adopted Clang due to its more permissive modification capabilities. As a result, many contemporary Objective-C features are exclusively supported by Clang.
Apple’s clang-based "LLVM compiler" employs a versioning system different from the open-source LLVM releases. See for additional information.
GNU, GNUstep, and WinObjC
The GNU project has long pursued porting NeXT and Objective-C software. The GCC runtime dates back prior to 1998 (GCC 2.95), with a significant rewrite occurring in 1993 (GCC 2.4).
NeXT’s frontend source was released under the GNU General Public License, mandating that derivative works remain open source. Apple maintained its GCC fork until version 4.2.1 before discontinuing it; subsequently, GCC maintainers integrated these modifications but lagged behind in supporting newer Objective-C 2.0 features.
In 2009, GNUstep developers branched GCC’s runtime into an independent project named , adapting it for compatibility with Clang to utilize updated language syntax. By version 4.6.0 (2011), GCC had caught up in supporting Objective-C 2.0, although GNUstep acknowledges ongoing deficiencies in areas such as blocks, non-fragile instance variables, and ARC support.
Microsoft incorporated a fork of ObjFW's runtime into WinObjC, its iOS compatibility layer for Universal Windows Platform applications, in 2015 and switched to a forked runtime in 2016. Alongside its own Cocoa Touch implementation, this facilitates the reuse of iOS application code within UWP apps.
On Windows platforms, GNUstep provides Objective-C development utilities including MSYS System, GNUstep Core and Devel packages, Cairo graphics integration, ProjectCenter IDE, and Gorm interface builder. However, these binary installers have not been refreshed since 2016; therefore, building within Cygwin or MSYS2 environments might be preferable for up-to-date development workflows.
Library use
Objective-C is frequently employed together with established libraries or frameworks such as Cocoa, GNUstep, and ObjFW. These libraries often come bundled with operating systems—GNUstep with various Linux distributions and Cocoa with macOS. Developers are not obligated to derive from the default base class (NSObject or OFObject) and may define new root classes without inheritance. Early Objective-C environments provided an Object base class; however, OpenStep introduced NSObject through NeXT to enhance capabilities like object referencing and reference counting. Almost all Cocoa classes now inherit from NSObject.
This transition also enabled legacy Object-based code to coexist alongside NSObject-based implementations within the same runtime environment. The convention of using two-letter prefixes emerged as an informal namespacing mechanism—a practice still widely adopted in the Objective-C community.
More recently, package managers such as CocoaPods have appeared, functioning both as repositories and installation tools that streamline the integration of open-source Objective-C libraries.
Analysis of the language
Objective-C utilizes a streamlined runtime environment primarily written in C, with some components of objc4 developed in C++, resulting in minimal additional size overhead compared to the substantial virtual machine runtimes that were common when it first emerged. Although Objective-C programs tend to be larger than their C or C++ counterparts—largely because dynamic typing prevents method elimination or inlining—they remain comparatively compact relative to Smalltalk implementations.
This language can be built on top of existing C compilers such as GCC, enabling extensive use of established C codebases, libraries, and development tools. By wrapping existing C libraries with Objective-C adapters, developers can create object-oriented interfaces, a strategy akin to the use of GObject and Vala within GTK development. This pragmatic method significantly eased adoption hurdles compared to the more complex Smalltalk systems from the 1980s.
One significant drawback is Objective-C’s absence of native namespace support; to prevent naming conflicts, developers conventionally employ class name prefixes (for example, "NS" in the Cocoa framework). As a strict superset of C, it does not treat primitive data types as first-class objects.
In contrast to C++, Objective-C does not offer operator overloading and supports only single inheritance. However, it compensates with categories and protocols that provide alternative means for extending functionality.
Because of its dynamic runtime typing model and message dispatch system, many compiler optimizations—such as function inlining and interprocedural analysis—cannot be applied, which restricts performance when compared to statically typed languages like C++.
Memory management
Initial versions of Objective-C did not include garbage collection, a decision influenced by concerns over prolonged pause times observed in Smalltalk environments. Some third-party solutions, notably GNUstep integrating the Boehm garbage collector, introduced this capability. Apple incorporated garbage collection starting with Mac OS X v10.5 but has since deprecated it in favor of Automatic Reference Counting (ARC), introduced in 2011.
ARC streamlines memory management by automatically inserting retain and release calls through static code analysis, thereby reducing the developer’s manual workload. It also brought weak references into Objective-C, improving both memory safety and application efficiency.
Philosophical differences between Objective-C and C++
Objective-C and C++ extend the C language through fundamentally distinct paradigms. While C++ supports procedural programming, object-oriented programming, generic programming, and metaprogramming—backed by an extensive standard library featuring numerous container classes—Objective-C focuses on object-oriented programming combined with dynamic typing and reflection but lacks a standardized library. Instead, it depends on frameworks such as OPENSTEP, Cocoa, or GNUstep to fulfill similar roles.
A major difference lies in Objective-C’s powerful runtime reflection capabilities that allow objects to dynamically disclose their abilities during execution. In contrast, C++ provides limited runtime introspection without relying on additional libraries. This dichotomy highlights the broader distinction: Objective-C prioritizes dynamic runtime features for adaptability, whereas C++ emphasizes static compile-time features for enhanced speed and type safety.
Both languages implement generic programming and metaprogramming through runtime polymorphism—C++ via virtual functions and runtime type identification; Objective-C through dynamic typing and reflection mechanisms. Compile-time polymorphism using generic functions is supported by both languages, with Objective-C introducing this feature in 2015.
See also
- C (programming language)
- C++
- CocoaPods
- Comparison of programming languages
- GNUStep
- Comparison with COM, GObject, SOM, Windows Runtime, XPCOM
- Swift (programming language)
- Xcode
- WinObjC (Windows Bridge for iOS)
Further reading
External links
- Programming with Objective-C, Apple (2012-12-13)
- The Objective-C Programming Language, Apple (2011-10-11)
- Objective-C Runtime Programming Guide, Apple (2009-10-19)
- GNUstep Base Programming Manual for Objective-C
- Objective-C tutorial by Brad Cox
- Objective-C Frequently Asked Questions
- Objective-C Code Examples ()