Objective-C é uma linguagem de programação com despacho dinâmico de mensagens, criada por Brad Cox na década de 1980. A Apple escolheu Objective-C como linguagem principal para NeXTSTEP e, posteriormente, para o iOS SDK. Programming With Objective-C — uma introdução à sintaxe de mensagens e gerenciamento de memória.
Pontos principais
Objective-C é uma linguagem de programação que estende C com capacidades de programação orientada a objetos no estilo Smalltalk. O código Objective-C é compilado via LLVM ou GCC em código de máquina nativo, mantendo compatibilidade reversa total com C — qualquer código C é válido em Objective-C.
A Apple adquiriu a NeXT (junto com Objective-C) em 1997. A linguagem tornou-se a base do Cocoa e Cocoa Touch — frameworks para macOS e iOS. Desde 2014, a Apple promove Swift como substituto, mas Objective-C continua sendo criticamente importante para projetos legados e alguns frameworks do sistema. De acordo com a Apple (WWDC 2024), cerca de 35% dos aplicativos na App Store ainda contêm código Objective-C.
A principal característica é o runtime dinâmico. Ao contrário do Swift, onde as chamadas de método são resolvidas em tempo de compilação, Objective-C envia mensagens em tempo de execução através da função objc_msgSend. Isso permite sobrescrever métodos em tempo real (method swizzling), adicionar classes dinamicamente e usar forward invocation para seletores inexistentes.
Qualquer código C é válido em Objective-C. A extensão orientada a objetos adiciona classes (@interface/@implementation), categorias, protocolos (@protocol) e tipagem dinâmica (id). Os arquivos têm extensões .m (implementação) e .h (cabeçalhos).
A sintaxe de mensagens é a principal diferença entre Objective-C e linguagens similares ao C. Em vez de object.method(argument), usa-se [object method:argument]. Cada mensagem passa pelo objc_msgSend, que busca dinamicamente a implementação do método no runtime.
// Sintaxe de mensagens com parâmetros nomeados
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];
// Mensagens aninhadas
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];
// Verificação de tipo via introspection
if ([object isKindOfClass:[UIView class]]) {
UIView *view = (UIView *)object;
view.backgroundColor = [UIColor redColor];
}O despacho dinâmico permite sobrescrever métodos em tempo de execução (method swizzling) — uma técnica poderosa mas perigosa. Por exemplo, frameworks como AFNetworking e Aspects usam swizzling para interceptar chamadas URLSession. A Apple alerta: swizzling pode quebrar frameworks do sistema se usado incorretamente.
As Categorias são uma característica única do Objective-C que permite adicionar métodos a classes existentes (incluindo classes do sistema como NSString e UIView) sem herança e sem acesso ao código-fonte. As categorias são declaradas através de @interface ClassName (CategoryName).
// Arquivo UIColor+Hex.h — categoria para UIColor
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end
// Arquivo UIColor+Hex.m — implementação
@implementation UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex {
CGFloat r = ((hex >> 16) & 0xFF) / 255.0;
CGFloat g = ((hex >> 8) & 0xFF) / 255.0;
CGFloat b = (hex & 0xFF) / 255.0;
return [self colorWithRed:r green:g blue:b alpha:1.0];
}
@endAs Extensões (Class Extension) são um tipo especial de categoria declarada em um arquivo .m sem nome: @interface ClassName (). Ao contrário das categorias, as extensões podem adicionar não apenas métodos, mas também ivar (variáveis de instância) e propriedades. Extensões são usadas para ocultar API interna de módulos externos.
Os Blocos são funções anônimas em Objective-C que capturam variáveis do escopo externo. Sintaxe de blocos: ^(int x) { return x * 2; }. Blocos são usados em UIKit para handlers de callback, em Grand Central Dispatch para tarefas assíncronas e em coleções NSArray/NSDictionary para operações funcionais.
// Declaração de tipo de bloco
typedef void (^CompletionBlock)(BOOL success, NSError *error);
// Bloco como parâmetro
- (void)fetchDataWithCompletion:(CompletionBlock)completion {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL result = [weakSelf processData];
if (completion) {
completion(result, nil);
}
});
}O gerenciamento de memória em blocos é criticamente importante. Blocos capturam self com uma referência forte, criando um retain cycle quando usados diretamente. A solução é __weak typeof(self) weakSelf = self, seguida de uma verificação dentro do bloco. Este problema está completamente resolvido em Swift através de capture lists [weak self].
Objective-C evoluiu de MRC (Manual Reference Counting) para ARC (Automatic Reference Counting). Em MRC, o desenvolvedor chamava manualmente retain (incrementar contador), release (decrementar) e autorelease (liberação adiada). Erros nessas chamadas levavam a vazamentos de memória ou crashes devido a ponteiros pendentes.
| Operação | MRC | ARC |
|---|---|---|
| Criação de objeto | [[Object alloc] init] | [[Object alloc] init] |
| Retenção de referência | [object retain] | Automaticamente |
| Liberação | [object release] | Automaticamente |
| Autoliberação | [object autorelease] | Automaticamente (não necessário) |
| Referência fraca | __weak não existia | __weak (nil automático) |
ARC foi introduzido no Xcode 4.2 e LLVM 3.0 (2011). O compilador insere automaticamente retain/release em tempo de compilação analisando o tempo de vida dos objetos. ARC não é coleta de lixo — é análise estática com inserções automáticas. ARC do Objective-C é compatível com ARC do Swift: ambos usam o mesmo sistema de contagem de referências no nível do runtime.
O uso conjunto de Objective-C e Swift em um mesmo projeto é uma prática comum para projetos legados. A Apple fornece o Bridging Header — um arquivo gerado automaticamente através do qual Swift vê as classes Objective-C, e Objective-C vê as classes Swift que herdam de NSObject.
// ProjectName-Bridging-Header.h
// Swift vê estes cabeçalhos automaticamente
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"A migração de Objective-C para Swift é um processo gradual. Novos arquivos são escritos em Swift, os antigos são gradualmente refatorados. O Bridging Header é gerado automaticamente ao adicionar o primeiro arquivo Swift a um projeto Objective-C. Para visibilidade reversa (ObjC → Swift), o Xcode gera um arquivo <ProjectName>-Swift.h contendo declarações @interface para classes Swift marcadas com @objc.
// Classe Swift visível do Objective-C
@objc class SwiftRouter: NSObject {
@objc func navigateToProfile(userId: Int) {
// implementação
}
}Limitações: tipos valor do Swift (struct, enum) não são visíveis diretamente do Objective-C — precisam ser encapsulados em uma classe com @objc. Os genéricos do Swift têm acessibilidade limitada do Objective-C. A abordagem recomendada é escrever código novo em Swift e refatorar o código Objective-C existente apenas ao alterar a funcionalidade correspondente.
A principal vantagem do Objective-C sobre o Swift é o acesso completo ao runtime. O method swizzling, substituindo implementações de métodos em tempo de execução, permite sobrescrever métodos do sistema sem herança. Bibliotecas como Aspects e JRSwizzle usam esta capacidade para AOP (programação orientada a aspectos) — monitoramento, análise e registro.
Forward invocation é outro recurso do runtime: se um objeto não responde a um seletor, o sistema chama forwardInvocation:, permitindo encaminhar a mensagem para outro objeto. Esta é a base do padrão Proxy em Objective-C (NSProxy), usado para inicialização preguiçosa e objetos distribuídos.
A Apple recomenda minimizar o uso de truques de runtime em código novo, preferindo a tipagem estática do Swift. No entanto, em projetos legados, o conhecimento de objc_msgSend, method_exchangeImplementations e objc_getAssociatedObject é necessário para manter a base de código existente.
Objective-C suporta propriedades como açúcar sintático sobre ivar com getters/setters. Os modificadores atomic/nonatomic, strong/weak/copy, readonly/readwrite e assign/retain determinam o comportamento de memória e a segurança de threads. Key-Value Observing (KVO) é um mecanismo para observar mudanças em propriedades, incorporado no runtime: qualquer objeto pode se inscrever em mudanças nas propriedades de outro objeto via addObserver.
Perguntas frequentes
Uma chamada de método se parece com [object selector:argument]. A mensagem passa pelo objc_msgSend, que encontra dinamicamente a implementação no runtime. Um seletor é um nome de método (@selector(methodName)), não um ponteiro de função. Isso permite swizzling e forward invocation.
Uma Categoria (@interface ClassName (Name)) adiciona métodos a qualquer classe (incluindo classes do sistema) sem herança. Uma Extensão (@interface ClassName ()) é declarada em um arquivo .m e pode adicionar propriedades e ivars. Uma Categoria não pode adicionar ivars, mas uma Extensão pode.
Blocos são funções anônimas com sintaxe ^(parâmetros) { corpo }, capturando variáveis do contexto. São análogos a lambdas em C++ e closures em Swift. Requerem __weak para prevenir retain cycles ao capturar self. São usados em UIKit, GCD e Foundation.
MRC é contagem manual de referências: o programador chama retain, release, autorelease. ARC é automático: o compilador insere retain/release baseado em análise estática. ARC não é GC — objetos são liberados imediatamente quando o contador chega a zero. ARC suporta modificadores __weak e __strong.
Sim, através de um Bridging Header. Swift vê Objective-C através deste cabeçalho, Objective-C vê Swift através de <ProjectName>-Swift.h. Classes Swift devem herdar de NSObject e ser marcadas com @objc. Structs e enums do Swift não são diretamente visíveis ao Objective-C.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também