CodeToLive

Cocoa & Cocoa Touch in Objective-C

Cocoa (macOS) and Cocoa Touch (iOS) are the application frameworks that provide the core infrastructure for building Mac and iOS apps.

Cocoa is the application framework for macOS development, while Cocoa Touch is the iOS/tvOS/watchOS equivalent, with UIKit replacing AppKit for user interface components.

Core Architecture

Model-View-Controller (MVC)


// Model
@interface Task : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic) BOOL completed;
@end

// View Controller
@interface TaskViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *completeButton;
@property (strong, nonatomic) Task *task;

- (IBAction)completeButtonTapped:(id)sender;
@end

@implementation TaskViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.titleLabel.text = self.task.title;
    [self updateCompleteButton];
}

- (void)updateCompleteButton {
    NSString *title = self.task.completed ? @"Completed" : @"Mark Complete";
    [self.completeButton setTitle:title forState:UIControlStateNormal];
}

- (IBAction)completeButtonTapped:(id)sender {
    self.task.completed = !self.task.completed;
    [self updateCompleteButton];
}
@end
            

Key Frameworks

Framework Purpose Key Classes
Foundation Core functionality NSString, NSArray, NSDictionary
AppKit (macOS) User interface NSWindow, NSView, NSButton
UIKit (iOS) User interface UIWindow, UIView, UIButton
Core Data Persistence NSManagedObject, NSManagedObjectContext
Core Animation Animations CALayer, CAAnimation

Application Lifecycle

iOS App Lifecycle


// AppDelegate.h
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

// AppDelegate.m
@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // App launched
    return YES;
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // App became active
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // App will become inactive
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // App entered background
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // App will enter foreground
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // App will terminate
}
@end
            

macOS App Lifecycle


// AppDelegate.h
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (strong, nonatomic) NSWindow *window;
@end

// AppDelegate.m
@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)notification {
    // App launched
}

- (void)applicationWillTerminate:(NSNotification *)notification {
    // App will terminate
}

- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
    return YES; // Quit when last window closed
}
@end
            

User Interface Components

Creating UI Programmatically


// Creating a button programmatically
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(20, 50, 280, 44);
[button setTitle:@"Tap Me" forState:UIControlStateNormal];
[button addTarget:self 
           action:@selector(buttonTapped:)
 forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];

// Creating a view controller
UIViewController *vc = [[UIViewController alloc] init];
vc.view.backgroundColor = [UIColor whiteColor];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 280, 30)];
label.text = @"Hello World";
[vc.view addSubview:label];
            

Using Storyboards and XIBs


// Loading from storyboard
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"DetailVC"];

// Loading from XIB
CustomView *view = [[[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil] firstObject];
            

Event Handling


// Target-action pattern
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
[button addTarget:self 
           action:@selector(buttonTapped:)
 forControlEvents:UIControlEventTouchUpInside];

// Gesture recognizers
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[self.view addGestureRecognizer:tap];

// Delegation
@interface MyViewController : UIViewController <UITextFieldDelegate>
@end

@implementation MyViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.textField.delegate = self;
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField {
    [textField resignFirstResponder];
    return YES;
}
@end
            

Core Data


// Core Data stack setup
@interface AppDelegate ()
@property (readonly, strong) NSPersistentContainer *persistentContainer;
@end

@implementation AppDelegate
- (NSPersistentContainer *)persistentContainer {
    if (_persistentContainer == nil) {
        _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"Model"];
        [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
            if (error != nil) {
                NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                abort();
            }
        }];
    }
    return _persistentContainer;
}
@end

// Creating and saving objects
NSManagedObjectContext *context = self.persistentContainer.viewContext;
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
person.name = @"John";
person.age = 30;

NSError *error = nil;
if (![context save:&error]) {
    NSLog(@"Error saving context: %@", error);
}

// Fetching objects
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"age > %@", @25];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
fetchRequest.sortDescriptors = @[sortDescriptor];

NSArray *people = [context executeFetchRequest:fetchRequest error:&error];
            

Networking


// URLSession data task
NSURL *url = [NSURL URLWithString:@"https://api.example.com/data"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];

NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (error) {
        NSLog(@"Error: %@", error);
        return;
    }
    
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    if (httpResponse.statusCode == 200) {
        NSError *jsonError;
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
        if (!jsonError) {
            dispatch_async(dispatch_get_main_queue(), ^{
                // Update UI with json data
            });
        }
    }
}];
[task resume];
            

Best Practices

Note: While Swift is now the preferred language for Apple development, many existing projects still use Objective-C, and understanding Cocoa/Cocoa Touch is valuable for maintaining them.

Next: Objective-C with Swift