← Back to Notes

Introduction to Objective-C

Objective-C is a general-purpose, object-oriented programming language that adds Smalltalk-style messaging to the C programming language. It was the main programming language used by Apple for macOS and iOS development before Swift. Think of it as C with a layer of object-oriented features on top.

Key Characteristics

  • Superset of C: Any valid C code is also valid Objective-C code. This is different from Python, which has its own distinct base syntax.
  • Object-Oriented: Like Python and C++, Objective-C supports encapsulation, inheritance, and polymorphism.
  • Dynamic Typing & Binding: Objective-C is more dynamic than C++. Decisions like what method to call can be deferred until runtime. Python is also dynamically typed.
  • Messaging: Instead of calling methods directly as in Python or C++, Objective-C sends messages to objects. The syntax is [receiver message].
  • Memory Management: Modern Objective-C primarily uses Automatic Reference Counting (ARC), which is similar in concept to Python's garbage collection but works at compile time by inserting memory management calls.

Basic Syntax & Structure

An Objective-C program generally consists of an interface file (.h) for declarations and an implementation file (.m) for the actual code.

Interface File (.h)

Declares classes, their properties, and method signatures. Similar to header files in C/C++.

// MyClass.h - Interface File
#import <Foundation/Foundation.h> // Import necessary frameworks

// MyClass inherits from NSObject (a common root class)
@interface MyClass : NSObject

// Properties (preferred way to declare instance variables and their accessors)
@property (nonatomic, strong) NSString *myStringProperty;
@property (nonatomic, assign) int myIntProperty;

// Method declarations
- (void)myInstanceMethod; // '-' denotes an instance method
+ (void)myClassMethod;    // '+' denotes a class method
- (NSString *)methodWithReturnValue;
- (void)methodWithParameter:(NSString *)paramName;
- (void)methodWithMultipleParameters:(NSString *)param1 andSecond:(NSInteger)param2;

@end

Implementation File (.m)

Contains the actual code for the methods declared in the interface.

// MyClass.m - Implementation File
#import "MyClass.h"

@implementation MyClass

- (void)myInstanceMethod {
    NSLog(@"This is an instance method."); // NSLog is like print() in Python
    self.myIntProperty = 20; // Access property using self
}

+ (void)myClassMethod {
    NSLog(@"This is a class method.");
}

- (NSString *)methodWithReturnValue {
    return @"Hello from method";
}

- (void)methodWithParameter:(NSString *)paramName {
    // %@ is a format specifier for objects
    NSLog(@"Received parameter: %@", paramName);
}

- (void)methodWithMultipleParameters:(NSString *)param1 andSecond:(NSInteger)param2 {
    // %ld for NSInteger
    NSLog(@"Param1: %@, Param2: %ld", param1, (long)param2);
}

@end

Data Types & Literals

Objective-C inherits C's basic data types and adds its own object types. Modern syntax makes creating objects very concise using literals.

  • C Primitive Types: int, float, double, char, BOOL (YES/NO).
  • Objective-C Objects:
    • id: A generic type for any Objective-C object pointer.
    • NSString: @"Hello, World!"
    • NSNumber: @42, @3.14f, @YES
    • NSArray: @[@"one", @"two", @"three"]
    • NSDictionary: @{@"key1": @"value1", @"key2": @2}
  • Constants: Defined with #define PI 3.14 or, preferably, the const qualifier: NSString * const MyConstantString = @"Immutable";

Control Flow

Control flow syntax is borrowed from C, but includes a powerful "fast enumeration" for looping through collections, similar to Python.

If-Else Statement

int score = 95;
if (score > 90) {
    NSLog(@"Excellent!");
} else if (score > 70) {
    NSLog(@"Good");
} else {
    NSLog(@"Keep trying");
}

Switch Statement

int day = 2;
switch (day) {
    case 1:
        NSLog(@"Sunday");
        break; // Without break, execution "falls through"
    case 2:
        NSLog(@"Monday");
        break;
    default:
        NSLog(@"Another day");
        break;
}

Loops

Includes C-style for, while, and do-while loops.

Fast Enumeration (for...in)

The preferred way to iterate over collections.

NSArray *colors = @[@"Red", @"Green", @"Blue"];
for (NSString *color in colors) {
    NSLog(@"Color: %@", color);
}

NSDictionary *capitals = @{@"USA": @"Washington D.C.", @"UK": @"London"};
for (NSString *country in capitals) { // Iterates through keys
    NSLog(@"The capital of %@ is %@", country, capitals[country]);
}

Objects, Classes, and Methods

Methods are functions associated with a class. Instance methods (-) operate on an object, while class methods (+) operate on the class itself.

Object Instantiation

Objects are created with a two-step alloc/init process.

// Standard way
MyClass *myObject = [[MyClass alloc] init];

// Calling a method on the new object
[myObject myInstanceMethod];

Properties

Properties automatically synthesize accessor methods (getters and setters) and are accessed using dot-notation.

// Using properties defined in the .h file from earlier
myObject.name = @"Alice";       // Setter -> [myObject setName:@"Alice"];
NSString *currentName = myObject.name; // Getter -> [myObject name];

Property Attributes

Attributes control memory management, atomicity, and mutability.

  • Memory (ARC): strong (default, owning reference), weak (non-owning, nil-ing reference), assign (for primitives), copy (creates a copy).
  • Atomicity: atomic (default, thread-safe get/set) or nonatomic (faster, not thread-safe).

Advanced Topics

Categories

Categories allow you to add methods to existing classes without subclassing, even to framework classes like NSString.

// A category to add a method to NSString
@interface NSString (MyAdditions)
- (NSString *)reversedString;
@end

@implementation NSString (MyAdditions)
- (NSString *)reversedString {
    NSMutableString *reversed = [NSMutableString string];
    for (NSInteger i = self.length - 1; i >= 0; i--) {
        [reversed appendFormat:@"%C", [self characterAtIndex:i]];
    }
    return reversed;
}
@end

// Usage:
NSString *rev = [@"hello" reversedString]; // returns @"olleh"

Protocols

Protocols define a set of required or optional methods a class can implement, similar to interfaces in other languages.

@protocol MyDataSourceProtocol <NSObject>
@required
- (NSInteger)numberOfItems;
- (NSString *)itemAtIndex:(NSInteger)index;
@optional
- (NSString *)titleForItemAtIndex:(NSInteger)index;
@end

// A class would conform like this:
// @interface MyClass : NSObject <MyDataSourceProtocol>
                

Blocks (Closures)

Blocks are Objective-C's version of lambdas or anonymous functions, commonly used for completion handlers and enumeration.

// Block that takes two integers and returns their sum
int (^addBlock)(int, int) = ^int(int a, int b) {
    return a + b;
};
int sum = addBlock(5, 3); // sum is 8

// Using a block to sort an array
NSArray *numbers = @[@3, @1, @4, @2];
NSArray *sortedNumbers = [numbers sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [obj1 compare:obj2]; // Ascending order
}];
// sortedNumbers is @[@1, @2, @3, @4]

Error Handling

The common pattern is for methods to return nil/NO on failure and populate an NSError object passed in as a pointer-to-a-pointer.

NSError *error = nil;
NSString *content = [NSString stringWithContentsOfFile:@"/path/to/nonexistent_file.txt"
                                              encoding:NSUTF8StringEncoding
                                                 error:&error];
if (content == nil) {
    // Error is populated by the method
    NSLog(@"Error reading file: %@", [error localizedDescription]);
} else {
    // Success! Use content.
}