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
- Follow MVC pattern but be aware of Massive View Controller problem
- Use storyboards for simple flows and XIBs for reusable components
- Keep business logic out of view controllers when possible
- Use dependency injection for better testability
- Perform heavy operations on background threads
- Always update UI on main thread
- Use Auto Layout for responsive interfaces
- Follow Apple's Human Interface Guidelines
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.