DevTools

Cheatsheet Objective-C

Linguagem orientada a objetos da Apple para macOS e iOS

Back to languages
Objective-C
62 cards found
Categories:
Versions:

Basic


9 cards
Primitive Types
int age = 30;
float pi = 3.14f;
double precise = 3.14159265;
BOOL active = YES;       // or NO
char c = 'A';
long big = 1000000L;

// Platform-safe Foundation types:
NSInteger count = 42;
CGFloat x = 3.14;

Objective-C uses the C types (int, float, double, char) plus BOOL (YES/NO). Prefer NSInteger and CGFloat because they are safe across platforms.

Modern Literals
// NSString:
NSString *name = @"Anna";

// NSNumber:
NSNumber *n = @42;
NSNumber *f = @3.14;
NSNumber *b = @YES;

// NSArray:
NSArray *arr = @[@"a", @"b", @"c"];

// NSDictionary:
NSDictionary *dict = @{
    @"name": @"Anna",
    @"age": @30
};

Modern literals use @ to create objects concisely: @42 (NSNumber), @[] (NSArray) and @{} (NSDictionary), replacing the long alloc/init methods.

Comments and Structure
// Line comment

/* Multi-line
   comment */

/// Documentation comment (HeaderDoc)

// Typical file structure:
// Person.h  -> @interface (declaration)
// Person.m  -> @implementation (code)

#import "Person.h"   // imports header

Comments use // and /* */; /// generates documentation. Each class splits into .h (public interface) and .m (implementation), linked by #import.

Message Syntax
// [receiver message]:
[array count];
[string length];

// With arguments (labels):
[array objectAtIndex:0];
[dict objectForKey:@"key"];
[string substringToIndex:5];

// Nested messages:
[[NSString alloc] initWithFormat:@"%d", 42];

Methods are called through messages between square brackets: [receiver message]. Each argument has a descriptive label, making the calls readable.

NSLog and Formatting
NSLog(@"Plain text");
NSLog(@"Age: %d", 30);            // int
NSLog(@"Name: %@", name);         // object
NSLog(@"Pi: %.2f", 3.14159);      // float
NSLog(@"Count: %lu", (unsigned long)n);
NSLog(@"Active: %d", active);     // BOOL

// %@ calls the object -description

NSLog prints to the console with format specifiers: %d (int), %f (float), %@ (object, calls description). It is the basic debugging tool.

Flow Control
if (age >= 18) {
    NSLog(@"Adult");
} else {
    NSLog(@"Minor");
}

for (int i = 0; i < 10; i++) { }

while (x > 0) { x--; }

// Fast enumeration:
for (NSString *item in array) {
    NSLog(@"%@", item);
}

The control structures come from C: if/else, for, while. The for...in (fast enumeration) iterates collections in a simple and fast way.

Operators
// Arithmetic:
int s = 2 + 3;     // 5
int d = 10 / 3;    // 3 (integer)
int r = 10 % 3;    // 1 (remainder)

// Comparison:
BOOL eq = (5 == 5);   // YES
BOOL gt = (5 > 3);    // YES

// Logical:
BOOL both = (a && b);    // AND
BOOL either = (a || b);  // OR
BOOL notA = !a;          // NOT

// Increment:
i++;  ++i;  i += 5;

The operators are the C ones: arithmetic (+ - * / %), comparison (== != > <) and logical (&& || !). Compound assignment (+=) and increment (++) are also available.

switch
switch (day) {
    case 1:
        NSLog(@"Monday");
        break;
    case 2:
        NSLog(@"Tuesday");
        break;
    default:
        NSLog(@"Other");
        break;
}

// Ternary:
NSString *r = (x > 0) ? @"pos" : @"neg";

The switch compares integer values, with case and default. Each case needs a break to avoid falling through to the next one. The ternary operator ? : is an inline if.

nil Messaging
Person *p = nil;

// Sending a message to nil does not crash:
NSString *name = [p name];   // nil
NSInteger n = [p count];     // 0
BOOL flag = [p isValid];     // NO

// Useful for checks:
if ([name length] > 0) {
    // only runs if name is not nil/empty
}

Sending a message to nil is safe and does not cause a crash — it returns nil, 0 or NO. This removes many null checks common in other languages.

Objects and Classes


9 cards
Declaring a Class (@interface)
// Person.h
#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic) NSInteger age;

- (NSString *)greeting;
- (instancetype)initWithName:(NSString *)name;

@end

The @interface in the .h file declares the class, its properties and the public methods. Instance methods start with -; the class inherits from NSObject.

super and Override
@implementation Student

// Override a parent method:
- (NSString *)greeting {
    NSString *base = [super greeting];
    return [base stringByAppendingString:
        @" (student)"];
}

@end

// super calls the parent class version

To override a method, redefine it in the subclass. super calls the parent class implementation, allowing the behavior to be extended instead of fully replaced.

Enumerations (NS_ENUM)
// Define a typed enum:
typedef NS_ENUM(NSInteger, OrderStatus) {
    OrderStatusPending,
    OrderStatusShipped,
    OrderStatusDelivered
};

// Use:
OrderStatus status = OrderStatusShipped;

if (status == OrderStatusShipped) {
    NSLog(@"Shipped");
}

// NS_OPTIONS for flags (bitmask)

The NS_ENUM macro defines enumerations with an explicit base type (e.g. NSInteger), safer than the C enum. NS_OPTIONS is used for combinable flags (bitmask).

Implementation (@implementation)
// Person.m
#import "Person.h"

@implementation Person

- (NSString *)greeting {
    return [NSString stringWithFormat:
        @"Hello, %@", self.name];
}

- (instancetype)initWithName:(NSString *)name {
    self = [super init];
    if (self) {
        _name = name;
    }
    return self;
}

@end

The @implementation in the .m file contains the method code. self refers to the current instance and _name is the instance variable (ivar) generated by the property.

Class Methods (+)
@interface Person : NSObject
// Instance method (-):
- (NSString *)details;
// Class method (+):
+ (instancetype)personWithName:(NSString *)name;
@end

@implementation Person
+ (instancetype)personWithName:(NSString *)name {
    Person *p = [[Person alloc] init];
    p.name = name;
    return p;
}
@end

// Usage: Person *p = [Person personWithName:@"Anna"];

Class methods start with + (instance ones with -). They are often used the factory methods (alternative constructors) that return instancetype.

Creating Objects
// alloc + init:
Person *p = [[Person alloc] init];
p.name = @"Anna";
p.age = 30;

// With custom initializer:
Person *p2 = [[Person alloc] initWithName:@"Ray"];

// Use:
NSLog(@"%@", [p greeting]);
NSLog(@"%ld years old", (long)p.age);

An object is created with alloc (allocates memory) followed by init (initializes). Properties are accessed with a dot (p.name) and methods through messages ([p greeting]).

id and instancetype
// id: pointer to any object
id object = @"a string";
object = @42;   // now it is NSNumber

// No compile-time type checking
[object length];   // runs at runtime

// instancetype: type of the receiving class
+ (instancetype)create;   // returns the right type

// Better than id in initializers/factories

The id type is a pointer to any object, without compile-time type checking. instancetype is preferable in initializers and factories, since it indicates the actual class type.

Inheritance
// Student.h
@interface Student : Person
@property (nonatomic, strong) NSString *school;
- (CGFloat)average;
@end

// Student.m
@implementation Student
- (CGFloat)average {
    return 16.5;
}
@end

Inheritance uses : ParentClass in the @interface. The subclass inherits properties and methods from the parent and can add its own. In Objective-C there is only single inheritance.

description and isEqual
@implementation Person

// Customize printing (NSLog %@):
- (NSString *)description {
    return [NSString stringWithFormat:
        @"<Person: %@, %ld>", self.name, (long)self.age];
}

// Equality:
- (BOOL)isEqual:(id)other {
    return [self.name isEqual:[other name]];
}

- (NSUInteger)hash {
    return self.name.hash;
}
@end

The description method defines the text shown by NSLog(@"%@", obj). To compare objects by value, override isEqual: and hash together.

Strings and Collections


8 cards
NSString
NSString *s = @"Hello World";

[s length];                  // 11
[s uppercaseString];         // "HELLO WORLD"
[s lowercaseString];         // "hello world"
[s substringToIndex:5];      // "Hello"
[s containsString:@"World"]; // YES
[s stringByAppendingString:@"!"];
[s componentsSeparatedByString:@" "];

NSString is immutable. Methods like uppercaseString, substringToIndex: and containsString: always return a new string, without changing the original.

NSMutableArray
NSMutableArray *m = [NSMutableArray
    arrayWithArray:@[@"Anna", @"Ray"]];

[m addObject:@"Joe"];
[m removeObjectAtIndex:1];
[m insertObject:@"X" atIndex:0];
[m replaceObjectAtIndex:0 withObject:@"Y"];

[m sortUsingSelector:@selector(compare:)];

NSMutableArray allows modifying the collection: addObject: adds, removeObjectAtIndex: removes, insertObject:atIndex: inserts and sortUsingSelector: sorts.

NSMutableString
NSMutableString *ms = [NSMutableString
    stringWithString:@"Hello World"];

[ms appendString:@"!"];
[ms replaceOccurrencesOfString:@"World"
    withString:@"ObjC"
    options:0
    range:NSMakeRange(0, ms.length)];

[ms deleteCharactersInRange:NSMakeRange(0, 6)];

NSMutableString is the mutable version: appendString: appends, replaceOccurrencesOfString: replaces and deleteCharactersInRange: removes, changing the string itself.

NSDictionary
NSDictionary *dict = @{
    @"name": @"Anna",
    @"age": @30
};

[dict objectForKey:@"name"];   // "Anna"
dict[@"name"];                 // "Anna" (subscript)
[dict count];                  // 2
[dict allKeys];                // all the keys
[dict allValues];              // all the values

NSDictionary stores immutable key-value pairs. Access uses objectForKey: or subscript dict[@"key"]. Keys must be unique and cannot be nil.

String Formatting
// stringWithFormat:
NSString *s = [NSString stringWithFormat:
    @"%@ is %ld years old", name, (long)age];

// With numbers:
NSString *price = [NSString stringWithFormat:
    @"%.2f EUR", 19.99];

// Join an array:
NSString *list = [array
    componentsJoinedByString:@", "];

stringWithFormat: creates formatted strings with specifiers (%@, %ld, %.2f). componentsJoinedByString: joins the elements of an array with a separator.

NSMutableDictionary
NSMutableDictionary *m = [NSMutableDictionary
    dictionaryWithDictionary:@{@"name": @"Anna"}];

// Add / update:
m[@"email"] = @"ana@mail.com";
[m setObject:@30 forKey:@"age"];

// Remove:
[m removeObjectForKey:@"age"];

[m removeAllObjects];

NSMutableDictionary allows changing the dictionary: assign by subscript (m[@"key"] = value) or with setObject:forKey:, and remove with removeObjectForKey:.

NSArray
NSArray *arr = @[@"Anna", @"Ray", @"Mia"];

[arr count];                 // 3
[arr objectAtIndex:0];       // "Anna"
arr[0];                      // "Anna" (subscript)
[arr containsObject:@"Ray"]; // YES
[arr firstObject];           // "Anna"
[arr lastObject];            // "Mia"

// Iterate:
for (NSString *name in arr) { }

NSArray is an ordered and immutable collection of objects. Access uses objectAtIndex: or the subscript syntax arr[0]. It does not accept nil values.

Collection Enumeration
// Fast enumeration:
for (NSString *item in array) {
    NSLog(@"%@", item);
}

for (NSString *key in dict) {
    NSLog(@"%@ = %@", key, dict[key]);
}

// Block enumeration:
[array enumerateObjectsUsingBlock:
    ^(id obj, NSUInteger idx, BOOL *stop) {
    NSLog(@"%lu: %@", (unsigned long)idx, obj);
}];

The for...in iterates arrays and dictionaries simply. Block enumeration (enumerateObjectsUsingBlock:) gives access to the index and allows stopping with *stop = YES.

Memory and Properties


8 cards
ARC
// ARC (Automatic Reference Counting):
// The compiler inserts retain/release

// You do not call [obj release] manually
Person *p = [[Person alloc] init];
// p has a strong reference

p = nil;   // releases the object (no refs)

// ARC handles memory at compile-time

ARC (Automatic Reference Counting) manages memory automatically at compile time, inserting retain/release. You never call release manually.

readonly and Custom Getter
@interface Person : NSObject
// Read-only (no public setter):
@property (nonatomic, readonly) NSInteger age;

// Getter with a custom name:
@property (nonatomic, getter=isActive) BOOL active;
@end

// Usage:
if (person.isActive) { }   // custom getter
person.age = 30;           // ERROR (readonly)

The readonly attribute prevents the generation of a public setter. The getter=isActive customizes the getter name, a common convention for boolean properties.

strong and weak
// strong (default): keeps the object alive
@property (nonatomic, strong) NSString *name;

// weak: does not retain (becomes nil when released)
@property (nonatomic, weak) id<Delegate> delegate;

// Example:
Person * __weak weakRef = person;
person = nil;
NSLog(@"%@", weakRef);   // (null)

A strong reference keeps the object alive; a weak one does not count toward the reference count and automatically becomes nil when the object is released, avoiding cycles.

Retain Cycles
// Problem: A strong -> B and B strong -> A
// Neither is released (memory leak)

// Solution: one weak reference
@interface Child : NSObject
@property (nonatomic, weak) Parent *parent;   // weak!
@end

@interface Parent : NSObject
@property (nonatomic, strong) Child *child;
@end

A retain cycle happens when two objects reference each other with strong, preventing deallocation. It is solved by making one of the references weak.

copy and assign
// copy: creates a copy (used with NSString)
@property (nonatomic, copy) NSString *title;

// assign: for primitive types (no ref count)
@property (nonatomic) NSInteger age;
@property (nonatomic) BOOL active;

// unsafe_unretained: like weak but does not become nil
@property (nonatomic, unsafe_unretained) id target;

copy creates a copy of the value (recommended for NSString and blocks). assign is for primitive types. unsafe_unretained is like weak but does not become nil — avoid it if possible.

weak/strong Dance in Blocks
// Avoid a retain cycle in blocks:
__weak typeof(self) weakSelf = self;

[self completeWithBlock:^{
    __strong typeof(weakSelf) strongSelf = weakSelf;
    if (!strongSelf) return;
    [strongSelf doSomething];
}];

In blocks that capture self, the weak/strong dance pattern is used: create a weakSelf to avoid the cycle and, inside the block, a temporary strongSelf to guarantee it exists during execution.

Properties
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic) NSInteger age;
@end

@implementation Person
// Automatically generates:
// - getter:  -name
// - setter:  -setName:
// - ivar:    _name
@end

// nonatomic: faster (not thread-safe)

A @property automatically generates the getter, the setter and the instance variable (_name). The nonatomic attribute makes access faster, giving up thread-safety.

dealloc and Cleanup
@implementation MyClass

- (void)dealloc {
    // Remove observers:
    [[NSNotificationCenter defaultCenter]
        removeObserver:self];

    // Close manual resources:
    [_file close];
    // ARC handles the rest
}

@end

The dealloc method is called when the object is released. It is used to remove observers and close manual resources. With ARC, you do not call [super dealloc] nor free memory manually.

Protocols and Blocks


8 cards
Protocols
// Define a protocol:
@protocol Healthy <NSObject>
- (void)exercise:(NSInteger)minutes;
@end

// Adopt it in the class:
@interface Person : NSObject <Healthy>
@end

@implementation Person
- (void)exercise:(NSInteger)minutes {
    NSLog(@"Exercised %ld min", (long)minutes);
}
@end

A @protocol defines a contract of methods (like an interface). The class adopts it between < > in the @interface and implements the required methods.

Blocks the Parameters
// Method that receives a block:
- (void)download:(NSURL *)url
    completion:(void (^)(BOOL success))handler {
    // ... asynchronous work ...
    handler(YES);
}

// Call:
[self download:url completion:^(BOOL ok) {
    if (ok) NSLog(@"Success!");
}];

Blocks are often passed the method parameters (callbacks). The syntax void (^)(BOOL) means a block that receives a BOOL and returns nothing.

@required and @optional
@protocol Healthy <NSObject>
@required
- (void)exercise:(NSInteger)minutes;

@optional
- (void)meditate;
@end

// Check before calling an optional method:
if ([person respondsToSelector:@selector(meditate)]) {
    [person meditate];
}

@required methods are mandatory (the default); @optional ones are not. Before calling an optional method, check with respondsToSelector: to avoid crashes.

Block typedef
// typedef for readability:
typedef void (^CompletionHandler)(BOOL success, NSError *error);

// Use in a property:
@property (nonatomic, copy) CompletionHandler onComplete;

// Use in a method:
- (void)download:(NSURL *)url
    completion:(CompletionHandler)handler {
    handler(YES, nil);
}

A typedef gives a readable name to a complex block type, making it easy to reuse in properties and method signatures. Block properties must be copy.

Delegates
@interface MyView : NSObject
@property (nonatomic, weak) id<MyDelegate> delegate;
@end

@implementation MyView
- (void)selectRow:(NSInteger)row {
    [self.delegate didSelectRow:row];
}
@end

// delegate is weak to avoid a retain cycle

The delegate pattern lets one object report events to another. The delegate property is weak (to avoid cycles) and typed with the protocol that defines the callbacks.

respondsToSelector
// Check if an object responds to a method:
if ([object respondsToSelector:@selector(meditate)]) {
    [object meditate];
}

// @selector creates a selector (method name)
SEL s = @selector(length);
[string performSelector:s];

// Useful for optional protocol methods

respondsToSelector: checks at runtime whether an object implements a method, avoiding crashes with optional methods. @selector() represents a method name the a value.

Blocks
// Declare and use a block:
void (^myBlock)(void) = ^{
    NSLog(@"Hello from the block!");
};
myBlock();

// With parameters and return value:
NSInteger (^add)(NSInteger, NSInteger) =
    ^NSInteger(NSInteger a, NSInteger b) {
    return a + b;
};
NSLog(@"%ld", (long)add(3, 4));   // 7

A block is a closure: code that captures its context. It is declared with ^. It can have parameters and a return value, and is widely used for callbacks and asynchronous code.

conformsToProtocol
// Check if it adopts a protocol:
if ([object conformsToProtocol:@protocol(Healthy)]) {
    id<Healthy> h = (id<Healthy>)object;
    [h exercise:30];
}

// isKindOfClass: checks the class
if ([object isKindOfClass:[Person class]]) {
    Person *p = (Person *)object;
}

conformsToProtocol: checks whether an object adopts a protocol, allowing a safe cast. isKindOfClass: does the same for the class. Both are runtime type checks.

Advanced


8 cards
Categories
// NSString+Utils.h
@interface NSString (Utils)
- (BOOL)containsDigit;
@end

// NSString+Utils.m
@implementation NSString (Utils)
- (BOOL)containsDigit {
    NSCharacterSet *ds =
        [NSCharacterSet decimalDigitCharacterSet];
    return [self rangeOfCharacterFromSet:ds]
        .location != NSNotFound;
}
@end

A category adds methods to an existing class without subclassing it, even system classes like NSString. The name goes between parentheses: NSString (Utils).

GCD (Grand Central Dispatch)
// Background + Main thread:
dispatch_async(dispatch_get_global_queue(
    DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // Heavy work here
    NSArray *data = [self process];

    dispatch_async(dispatch_get_main_queue(), ^{
        // Update the UI here
        self.label.text = @"Done";
    });
});

GCD manages concurrency with queues. dispatch_async to a global queue runs work in the background; then it goes back to the main queue to update the UI (mandatory on iOS).

Class Extensions
// Person.m (at the top, before @implementation)
@interface Person ()
// Private properties:
@property (nonatomic) NSInteger counter;
- (void)internalMethod;
@end

@implementation Person
- (void)internalMethod {
    self.counter++;
}
@end

A class extension (anonymous category, ()) declares private properties and methods in the .m file. It is only visible inside the implementation, unlike named categories.

dispatch_after
// Run after a delay:
dispatch_after(
    dispatch_time(DISPATCH_TIME_NOW,
        2 * NSEC_PER_SEC),
    dispatch_get_main_queue(), ^{
    NSLog(@"After 2 seconds");
});

// dispatch_once: runs only once (singleton)
static dispatch_once_t once;
dispatch_once(&once, ^{
    instance = [[self alloc] init];
});

dispatch_after schedules a block with a delay (in nanoseconds). dispatch_once guarantees a block runs only once, being the classic pattern to implement singletons.

KVC (Key-Value Coding)
// Access properties by name (string):
NSString *name = [person valueForKey:@"name"];
[person setValue:@"Anna" forKey:@"name"];

// Map over collections:
NSArray *names = [people valueForKey:@"name"];

// Aggregation:
NSNumber *max = [numbers valueForKeyPath:@"@max.self"];

KVC allows accessing properties by name (string) with valueForKey: and setValue:forKey:. The valueForKeyPath: supports aggregation operators like @max.

NSError
// NSError pattern (passed by reference):
NSError *error = nil;
NSString *content = [NSString
    stringWithContentsOfFile:@"/tmp/f.txt"
    encoding:NSUTF8StringEncoding
    error:&error];

if (error) {
    NSLog(@"Error: %@", error.localizedDescription);
    NSLog(@"Code: %ld", (long)error.code);
}

In Objective-C, errors use the NSError pattern passed by reference (&error). If as method fails, it fills in the error; check whether it is nil before using it.

KVO (Key-Value Observing)
// Observe a change on a property:
[person addObserver:self
    forKeyPath:@"name"
    options:NSKeyValueObservingOptionNew
    context:NULL];

// Callback called on change:
- (void)observeValueForKeyPath:(NSString *)keyPath
    ofObject:(id)object
    change:(NSDictionary *)change
    context:(void *)context {
    NSLog(@"New: %@", change[NSKeyValueChangeNewKey]);
}

KVO notifies automatically when a property changes. You register with addObserver:forKeyPath: and receive the notification in observeValueForKeyPath: with the new value.

NSNotificationCenter
// Subscribe to a notification:
[[NSNotificationCenter defaultCenter]
    addObserver:self
    selector:@selector(dataReceived:)
    name:@"DataUpdated"
    object:nil];

// Post a notification:
[[NSNotificationCenter defaultCenter]
    postNotificationName:@"DataUpdated"
    object:nil];

// Remove (in dealloc)

NSNotificationCenter is a global publish/subscribe system. Subscribe with addObserver:selector:name: and post with postNotificationName:, decoupling objects.

Cocoa e Frameworks


6 cards
Foundation vs UIKit
// Foundation: base types (macOS + iOS)
#import <Foundation/Foundation.h>
// NSString, NSArray, NSDictionary, NSURL...

// UIKit: interface (iOS only)
#import <UIKit/UIKit.h>
// UIView, UIViewController, UILabel...

// AppKit: interface (macOS only)
#import <AppKit/AppKit.h>

The Foundation framework provides the base types (strings, collections, dates) on all platforms. UIKit (iOS) and AppKit (macOS) provide the graphical interface.

NSURL and NSURLSession
NSURL *url = [NSURL URLWithString:
    @"https://api.example.com/data"];

NSURLSession *session = [NSURLSession sharedSession];

NSURLSessionDataTask *task = [session
    dataTaskWithURL:url
    completionHandler:^(NSData *data,
        NSURLResponse *resp, NSError *error) {
    if (!error) {
        // process the data
    }
}];
[task resume];

NSURL represents an address. NSURLSession makes asynchronous network requests; dataTaskWithURL: creates the task and the completionHandler receives the data. Call resume to start.

NSUserDefaults
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];

// Save:
[prefs setObject:@"Anna" forKey:@"name"];
[prefs setInteger:30 forKey:@"age"];
[prefs setBool:YES forKey:@"active"];
[prefs synchronize];

// Read:
NSString *name = [prefs stringForKey:@"name"];
NSInteger age = [prefs integerForKey:@"age"];

NSUserDefaults stores small persistent preferences (settings). Use setObject:forKey: to save and objectForKey: (or typed variants) to read.

NSDate and NSDateFormatter
// Current date:
NSDate *now = [NSDate date];

// Format to string:
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm"];
NSString *text = [fmt stringFromDate:now];

// Parse a string into a date:
NSDate *date = [fmt dateFromString:@"2024-01-15 10:30"];

NSDate represents an instant in time. NSDateFormatter converts between dates and strings with a format defined by setDateFormat: (e.g. yyyy-MM-dd).

NSFileManager
NSFileManager *fm = [NSFileManager defaultManager];

// Check existence:
BOOL exists = [fm fileExistsAtPath:@"/tmp/f.txt"];

// Create a folder:
[fm createDirectoryAtPath:@"/tmp/folder"
    withIntermediateDirectories:YES
    attributes:nil error:nil];

// List contents:
NSArray *items = [fm contentsOfDirectoryAtPath:@"/tmp"
    error:nil];

NSFileManager manages the file system: check existence with fileExistsAtPath:, create folders with createDirectoryAtPath: and list contents with contentsOfDirectoryAtPath:.

JSON (NSJSONSerialization)
// JSON -> objects:
NSDictionary *json = [NSJSONSerialization
    JSONObjectWithData:data
    options:0 error:&error];

// objects -> JSON:
NSData *output = [NSJSONSerialization
    dataWithJSONObject:dict
    options:NSJSONWritingPrettyPrinted
    error:&error];

NSString *text = [[NSString alloc]
    initWithData:output encoding:NSUTF8StringEncoding];

NSJSONSerialization converts between JSON and Foundation objects. JSONObjectWithData: parses NSData into dictionaries/arrays; dataWithJSONObject: does the reverse.

Tools and Patterns


6 cards
.h / .m Structure
// Person.h (public interface)
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
- (NSString *)greeting;
@end

// Person.m (implementation)
#import "Person.h"
@implementation Person
- (NSString *)greeting {
    return [NSString stringWithFormat:@"Hello, %@", self.name];
}
@end

Each class splits into two files: the .h (header) declares the public interface and the .m (implementation) contains the code. The .m imports its own .h.

Modern Objective-C
// Literals (modern):
NSArray *arr = @[@1, @2, @3];
NSNumber *n = @42;

// Subscripting:
id obj = arr[0];
dict[@"key"] = value;

// instancetype instead of id:
+ (instancetype)create;

// NS_ENUM / NS_OPTIONS:
typedef NS_ENUM(NSInteger, Color) { ColorBlue };

Modern Objective-C uses literals (@[], @42), subscripting (arr[0]), instancetype and NS_ENUM. These features make the code more concise and safer.

#import and #include
// #import: includes only once (recommended)
#import "Person.h"          // local header
#import <Foundation/Foundation.h>  // framework

// #include: may include multiple times (C)
#include "utils.h"

// @class: forward declaration (in the .h)
@class Person;   // avoids importing the full header

#import includes a header guaranteeing it is only read once (preferable to #include). @class is a forward declaration used in the .h to avoid circular dependencies.

Best Practices
// 1. Properties instead of public ivars
@property (nonatomic, copy) NSString *name;

// 2. NSString the copy
// 3. delegate the weak
// 4. nil checks on optionals
if ([obj respondsToSelector:@selector(m)]) { }

// 5. Errors via NSError**, not exceptions
// 6. Immutability by default
//    (NSArray, not NSMutableArray)

Best practices: use properties, mark NSString the copy and delegate the weak, handle errors via NSError (not exceptions) and prefer immutable collections by default.

Compilation
# Compile with clang:
clang -framework Foundation main.m -o program

# Run:
./program

# In Xcode:
# Cmd+B  -> build
# Cmd+R  -> build & run

# Compiled files:
# .m  -> .o (object) -> executable

The clang compiler turns .m into an executable; the -framework Foundation flag links the framework. In Xcode, Cmd+B builds and Cmd+R runs.

Prefixes and Conventions
// 2-3 letter prefixes (avoid conflicts):
@interface ABCPerson : NSObject
@end

// Naming conventions:
// Classes:    PascalCase (ABCPerson)
// Methods:    camelCase (countItems)
// Properties: camelCase (firstName)
// Constants:  kPrefix (kMaxAttempts)

static const NSInteger kMaxAttempts = 3;

Classes use a 2-3 letter prefix (e.g. NS, UI, ABC) to avoid name conflicts. Classes in PascalCase, methods and properties in camelCase, constants with k.