Programación · Lenguajes de programación
Tutorial de Objective-C para principiantes
Respuesta corta
Objective-C es C con mensajería orientada a objetos al estilo Smalltalk añadida encima. Llamas a los métodos enviando mensajes entre corchetes, [object doSomething:arg], defines clases en bloques @interface y @implementation, y usas el framework Foundation de Apple para cadenas, arreglos y diccionarios. Fue el lenguaje principal de las apps de macOS e iOS antes de Swift y todavía se usa en muchas bases de código existentes de Apple. En un Mac, compila con clang -fobjc-arc -framework Foundation hello.m.
Qué es Objective-C y quién lo usa
Objective-C fue creado por Brad Cox y Tom Love a principios de los años 80, NeXT lo adoptó para su sistema NeXTSTEP y lo heredó Apple, donde NeXTSTEP se convirtió en la base de macOS e iOS. Es un superconjunto estricto de C: cualquier código C es Objective-C válido, y puedes mezclar ambos libremente.
Hoy Apple recomienda Swift para las apps nuevas, pero Objective-C sigue plenamente soportado. Se encuentra en apps antiguas de iOS y macOS, en muchos frameworks del sistema y bibliotecas de terceros, y en proyectos que combinan C o C++ con las API de Apple. Swift y Objective-C interoperan en el mismo proyecto, así que conocer ambos es útil para quien desarrolla para plataformas Apple.
Instala y ejecuta Hello, world
En macOS, instala Xcode o solo las herramientas de línea de comandos (xcode-select --install), que incluyen el compilador clang y el framework Foundation. Los archivos fuente usan la extensión .m; los de cabecera usan .h.
// hello.m
#import <Foundation/Foundation.h>
int main(void) {
@autoreleasepool {
NSLog(@"Hello, world!");
}
return 0;
}clang -fobjc-arc -framework Foundation hello.m -o hello
./hello
# 2026-10-31 10:00:00.000 hello[1234:5678] Hello, world!NSLog escribe en la salida de error estándar y añade una marca de tiempo y el nombre del proceso. @"..." crea un objeto NSString en lugar de una cadena de C. -fobjc-arc activa el conteo automático de referencias (ARC), la gestión de memoria estándar. En Linux, el proyecto GNUstep ofrece una biblioteca Foundation compatible, con comandos de compilación distintos.
Tipos, objetos y mensajes
Como Objective-C es C, todos los tipos de C funcionan. Los objetos siempre se usan mediante punteros (NSString *name). Llamar a un método se llama enviar un mensaje; los argumentos se intercalan con las partes del nombre del método.
| Tipo | Ejemplo | Notas |
|---|---|---|
| Números de C | int, double, NSInteger | NSInteger es de 64 bits en plataformas de 64 bits |
| BOOL | BOOL ok = YES; | YES / NO |
| NSString * | @"hello" | Objeto de cadena inmutable |
| NSNumber * | @42, @3.14, @(x + 1) | Envuelve un número para que las colecciones puedan contenerlo |
| id | id thing = @"x"; | Puntero a cualquier objeto, sin tipo estático |
| nil | nil | El puntero nulo a objeto |
NSString *name = @"Ana";
NSInteger age = 30;
NSString *line = [NSString stringWithFormat:@"%@ is %ld", name, (long)age];
NSLog(@"%@", line); // Ana is 30
NSLog(@"%lu", (unsigned long)[name length]); // 3
NSString *upper = [name uppercaseString]; // @"ANA"
BOOL same = [name isEqualToString:@"Ana"]; // YES
NSString *nothing = nil;
NSLog(@"%lu", (unsigned long)[nothing length]); // 0: messages to nil return 0En las cadenas de formato, %@ imprime un objeto (llama a su método description). Enviar un mensaje a nil está permitido y devuelve nil o 0, lo que evita muchos fallos pero también puede ocultar errores.
Control de flujo
El control de flujo es exactamente el de C: if, else, switch, for, while y do ... while. Objective-C añade la enumeración rápida con for ... in para las colecciones.
NSInteger score = 85;
if (score >= 90) {
NSLog(@"A");
} else if (score >= 80) {
NSLog(@"B");
} else {
NSLog(@"C");
}
for (int i = 1; i <= 3; i++) {
NSLog(@"%d squared is %d", i, i * i);
}
for (NSString *fruit in @[@"apple", @"pear"]) {
NSLog(@"%@", fruit);
}Clases, propiedades y métodos
Una clase tiene una interfaz pública (normalmente en un archivo .h) y una implementación (en el archivo .m). Los métodos de instancia empiezan con - y los de clase con +. @property declara una propiedad y genera su getter, su setter y una variable de respaldo con nombre que empieza por guion bajo.
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic) NSInteger age;
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age;
- (NSString *)greeting;
@end
@implementation Person
- (instancetype)initWithName:(NSString *)name age:(NSInteger)age {
self = [super init];
if (self) {
_name = [name copy];
_age = age;
}
return self;
}
- (NSString *)greeting {
return [NSString stringWithFormat:@"Hi, I am %@, %ld", self.name, (long)self.age];
}
@end
// Usage inside main:
Person *ana = [[Person alloc] initWithName:@"Ana" age:30];
NSLog(@"%@", [ana greeting]); // Hi, I am Ana, 30
ana.age = 31; // dot syntax calls the setterLos objetos se crean en dos pasos: alloc reserva memoria y un método init... la inicializa. El método anterior se llama initWithName:age: (los dos puntos son parte del nombre). Los protocolos (@protocol) cumplen el papel de las interfaces, y las categorías permiten añadir métodos a clases existentes, incluso a NSString.
Colecciones de Foundation y bloques
El framework Foundation ofrece colecciones inmutables y subclases mutables. Los literales hacen que sean cortas de escribir. Las colecciones solo contienen objetos, así que los números se envuelven como NSNumber, y no se puede almacenar nil (usa [NSNull null] en su lugar).
| Clase | Literal o creación | Versión mutable |
|---|---|---|
| NSArray | @[@"Ana", @"Ben"] | NSMutableArray |
| NSDictionary | @{@"Ana": @30} | NSMutableDictionary |
| NSSet | [NSSet setWithArray:arr] | NSMutableSet |
| NSString | @"text" | NSMutableString |
NSArray<NSString *> *names = @[@"Ana", @"Ben"];
NSMutableArray<NSString *> *more = [names mutableCopy];
[more addObject:@"Cleo"];
NSDictionary<NSString *, NSNumber *> *ages = @{@"Ana": @30, @"Ben": @17};
NSLog(@"%lu names, Ana is %@", (unsigned long)more.count, ages[@"Ana"]);
NSInteger (^square)(NSInteger) = ^(NSInteger x) { return x * x; };
NSLog(@"%ld", (long)square(7)); // 49
NSArray<NSNumber *> *sorted = [@[@3, @1, @2]
sortedArrayUsingComparator:^NSComparisonResult(NSNumber *a, NSNumber *b) {
return [a compare:b];
}];
NSLog(@"%@", [sorted componentsJoinedByString:@", "]); // 1, 2, 3Los bloques, escritos con ^, son clausuras: funciones anónimas que capturan variables del ámbito que las rodea. Las API de Apple los usan para callbacks, ordenación y trabajo asíncrono con Grand Central Dispatch. Las partes <NSString *> son genéricos ligeros que ayudan al compilador y a Swift; son opcionales.
Gestión de memoria y manejo de errores
Con ARC, el compilador inserta por ti las llamadas de conteo de referencias: un objeto se libera cuando ninguna referencia fuerte apunta a él. Solo necesitas romper los ciclos de referencias, normalmente marcando uno de los lados como weak (por ejemplo, una propiedad delegate).
Los errores recuperables usan el patrón NSError: un método devuelve nil o NO al fallar y rellena un objeto NSError pasado por referencia. Las excepciones (@try, @catch, NSException) existen, pero en Cocoa señalan errores del programador, como un índice fuera de rango, no fallos normales.
NSError *error = nil;
NSString *text = [NSString stringWithContentsOfFile:@"/no/such/file"
encoding:NSUTF8StringEncoding
error:&error];
if (text == nil) {
NSLog(@"Failed: %@", error.localizedDescription);
}Un programa pequeño y completo: frecuencia de palabras
#import <Foundation/Foundation.h>
int main(void) {
@autoreleasepool {
NSString *text = @"the cat and the hat and the bat";
NSMutableDictionary<NSString *, NSNumber *> *counts = [NSMutableDictionary dictionary];
for (NSString *word in [text componentsSeparatedByString:@" "]) {
counts[word] = @(counts[word].integerValue + 1);
}
NSArray<NSString *> *sorted = [counts keysSortedByValueUsingComparator:
^NSComparisonResult(NSNumber *a, NSNumber *b) { return [b compare:a]; }];
for (NSString *word in [sorted subarrayWithRange:NSMakeRange(0, 2)]) {
printf("%s %ld\n", word.UTF8String, (long)counts[word].integerValue);
}
}
return 0;
}
// the 3
// and 2Para una palabra nueva, counts[word] es nil, y nil.integerValue devuelve 0, así que la primera cuenta pasa a ser 1. El comparador invierte el orden para ordenar por frecuencia de mayor a menor, y printf imprime sin el prefijo de NSLog.
Adónde ir después
- La guía «Programming with Objective-C» de Apple en el archivo de documentación, para los fundamentos del lenguaje.
- La referencia del framework Foundation en la documentación para desarrolladores de Apple.
- La documentación de Clang sobre el conteo automático de referencias, para las reglas exactas de memoria.
- Aprende cómo trabajan juntos Objective-C y Swift si mantienes una base de código mixta.
Preguntas frecuentes
¿Se sigue usando Objective-C?
Sí, sobre todo en apps y bibliotecas existentes de iOS y macOS. Apple recomienda Swift para código nuevo, pero Xcode y los SDK de Apple siguen dando soporte a Objective-C.
¿Debería aprender primero Swift u Objective-C?
Para desarrollo nuevo en Apple, aprende primero Swift. Aprende Objective-C cuando necesites leer o mantener código antiguo, usar de cerca bibliotecas de C o C++, o entender cómo funcionan por debajo los frameworks de Apple.
¿Qué significan los corchetes en Objective-C?
Envían un mensaje: [receiver message] llama al método message del objeto receiver. Los argumentos van después de los dos puntos, como en [dict setObject:value forKey:key].
¿Objective-C tiene recolección de basura?
El Objective-C moderno usa el conteo automático de referencias (ARC), en el que el compilador añade las llamadas retain y release. El antiguo recolector de basura de Apple para macOS quedó obsoleto y ya no está disponible.