Objective-C: l'essenza del linguaggio e il suo posto nello sviluppo iOS

Autore: IT Sectr Pubblicato: 2026-02-09 Tempo di lettura: 8 min

Objective-C è un linguaggio di programmazione con dispatch dinamico dei messaggi, creato da Brad Cox negli anni '80. Apple ha scelto Objective-C come linguaggio principale per NeXTSTEP e successivamente per l'iOS SDK. Programming With Objective-C — un'introduzione alla sintassi dei messaggi e alla gestione della memoria.

Punti chiave

  • Objective-C — un superinsieme stretto di C con sintassi a messaggi tra parentesi quadre e un runtime dinamico
  • Message passing — chiamate a metodo tramite [object selector:argument] con ricerca dinamica dell'implementazione attraverso objc_msgSend
  • Categories — meccanismo per aggiungere metodi a classi esistenti senza ereditarietà e senza accesso al codice sorgente
  • Blocks — funzioni anonime con chiusure, predecessore delle closure di Swift
  • ARC vs MRC — conteggio automatico e manuale dei riferimenti per la gestione della memoria

Cos'è Objective-C?

Objective-C è un linguaggio di programmazione che estende C con capacità di programmazione orientata agli object in stile Smalltalk. Il codice Objective-C viene compilato tramite LLVM o GCC in codice macchina nativo, mantenendo la piena compatibilità all'indietro con C — qualsiasi codice C è valido in Objective-C.

Apple ha acquisito NeXT (insieme a Objective-C) nel 1997. Il linguaggio è diventato la base di Cocoa e Cocoa Touch — i framework per macOS e iOS. Dal 2014, Apple promuove Swift come sostituto, ma Objective-C rimane criticamente importante per progetti legacy e alcuni framework di sistema. Secondo Apple (WWDC 2024), circa il 35% delle app nell'App Store contiene ancora codice Objective-C.

La caratteristica principale è il runtime dinamico. A differenza di Swift, dove le chiamate ai metodi vengono risolte in fase di compilazione, Objective-C invia messaggi in fase di esecuzione attraverso la funzione objc_msgSend. Ciò consente di sovrascrivere metodi al volo (method swizzling), aggiungere classi dinamicamente e utilizzare forward invocation per selettori inesistenti.

Sintassi: C + estensione orientata agli oggetti

Qualsiasi codice C è valido in Objective-C. L'estensione orientata agli oggetti aggiunge classi (@interface/@implementation), categorie, protocolli (@protocol) e tipizzazione dinamica (id). I file hanno estensioni .m (implementazione) e .h (intestazioni).

Sintassi dei messaggi e dispatch dinamico

La sintassi dei messaggi è la differenza principale tra Objective-C e i linguaggi simili a C. Invece di object.method(argument), si usa [object method:argument]. Ogni messaggio passa attraverso objc_msgSend, che cerca dinamicamente l'implementazione del metodo nel runtime.

objective-c
// Sintassi dei messaggi con parametri nominati
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];

// Messaggi annidati
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];

// Controllo del tipo tramite introspection
if ([object isKindOfClass:[UIView class]]) {
    UIView *view = (UIView *)object;
    view.backgroundColor = [UIColor redColor];
}

Il dispatch dinamico consente di sovrascrivere metodi in fase di esecuzione (method swizzling) — una tecnica potente ma pericolosa. Ad esempio, framework come AFNetworking e Aspects usano lo swizzling per intercettare le chiamate URLSession. Apple avverte: lo swizzling può rompere i framework di sistema se usato in modo errato.

Categorie ed estensioni di classe

Le Categorie sono una caratteristica unica di Objective-C che consente di aggiungere metodi a classi esistenti (incluse classi di sistema come NSString e UIView) senza ereditarietà e senza accesso al codice sorgente. Le categorie vengono dichiarate tramite @interface ClassName (CategoryName).

objective-c
// File UIColor+Hex.h — categoria per UIColor
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end

// File UIColor+Hex.m — implementazione
@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];
}
@end

Le Estensioni (Class Extension) sono un tipo speciale di categoria dichiarata in un file .m senza nome: @interface ClassName (). A differenza delle categorie, le estensioni possono aggiungere non solo metodi ma anche ivar (variabili di istanza) e proprietà. Le estensioni vengono utilizzate per nascondere l'API interna dai moduli esterni.

Blocchi (Blocks) — funzioni anonime con chiusure

I Blocchi sono funzioni anonime in Objective-C che catturano variabili dall'ambito esterno. Sintassi dei blocchi: ^(int x) { return x * 2; }. I blocchi vengono utilizzati in UIKit per i gestori di callback, in Grand Central Dispatch per attività asincrone e nelle collezioni NSArray/NSDictionary per operazioni funzionali.

objective-c
// Dichiarazione del tipo di blocco
typedef void (^CompletionBlock)(BOOL success, NSError *error);

// Blocco come parametro
- (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);
        }
    });
}

La gestione della memoria nei blocchi è criticamente importante. I blocchi catturano self con un riferimento forte, creando un retain cycle se usati direttamente. La soluzione è __weak typeof(self) weakSelf = self, seguita da un controllo all'interno del blocco. Questo problema è completamente risolto in Swift tramite le capture lists [weak self].

ARC e MRC: gestione della memoria

Objective-C si è evoluto da MRC (Manual Reference Counting) ad ARC (Automatic Reference Counting). In MRC, lo sviluppatore chiamava manualmente retain (incrementare contatore), release (decrementare) e autorelease (rilascio differito). Errori in queste chiamate portavano a perdite di memoria o crash a causa di puntatori pendenti.

OperazioneMRCARC
Creazione oggetto[[Object alloc] init][[Object alloc] init]
Ritenzione riferimento[object retain]Automaticamente
Rilascio[object release]Automaticamente
Autorilascio[object autorelease]Automaticamente (non richiesto)
Riferimento debole__weak non esisteva__weak (nil automatico)

ARC è stato introdotto in Xcode 4.2 e LLVM 3.0 (2011). Il compilatore inserisce automaticamente retain/release in fase di compilazione analizzando la vita degli oggetti. ARC non è garbage collection — è analisi statica con inserimenti automatici. L'ARC di Objective-C è compatibile con l'ARC di Swift: entrambi usano lo stesso sistema di conteggio dei riferimenti a livello di runtime.

Interoperabilità con Swift tramite Bridging Header

L'uso congiunto di Objective-C e Swift in un unico progetto è una pratica comune per progetti legacy. Apple fornisce il Bridging Header — un file generato automaticamente attraverso il quale Swift vede le classi Objective-C e Objective-C vede le classi Swift che ereditano da NSObject.

objective-c
// ProjectName-Bridging-Header.h
// Swift vede queste intestazioni automaticamente
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"

La migrazione da Objective-C a Swift è un processo graduale. I nuovi file vengono scritti in Swift, i vecchi vengono gradualmente rifattorizzati. Il Bridging Header viene generato automaticamente quando si aggiunge il primo file Swift a un progetto Objective-C. Per la visibilità inversa (ObjC → Swift), Xcode genera un file <ProjectName>-Swift.h contenente dichiarazioni @interface per le classi Swift marcate con @objc.

swift
// Classe Swift visibile da Objective-C
@objc class SwiftRouter: NSObject {
    @objc func navigateToProfile(userId: Int) {
        // implementazione
    }
}

Limitazioni: i tipi valore di Swift (struct, enum) non sono visibili direttamente da Objective-C — devono essere incapsulati in una classe con @objc. I generics di Swift hanno accessibilità limitata da Objective-C. L'approccio consigliato è scrivere nuovo codice in Swift e rifattorizzare il codice Objective-C esistente solo quando si modifica la funzionalità corrispondente.

Runtime e Method Swizzling in Objective-C

Il principale vantaggio di Objective-C rispetto a Swift è l'accesso completo al runtime. Il method swizzling, che sostituisce le implementazioni dei metodi in fase di esecuzione, consente di sovrascrivere metodi di sistema senza ereditarietà. Librerie come Aspects e JRSwizzle usano questa capacità per AOP (programmazione orientata agli aspetti) — monitoraggio, analisi e registrazione.

Forward invocation è un'altra funzionalità del runtime: se un oggetto non risponde a un selettore, il sistema chiama forwardInvocation:, consentendo di inoltrare il messaggio a un altro oggetto. Questa è la base del pattern Proxy in Objective-C (NSProxy), utilizzato per inizializzazione pigra e oggetti distribuiti.

Apple raccomanda di minimizzare l'uso di trucchi del runtime nel nuovo codice, preferendo la tipizzazione statica di Swift. Tuttavia, in progetti legacy, la conoscenza di objc_msgSend, method_exchangeImplementations e objc_getAssociatedObject è necessaria per mantenere la base di codice esistente.

Proprietà e Key-Value Observing

Objective-C supporta le proprietà come zucchero sintattico su ivar con getter/setter. I modificatori atomic/nonatomic, strong/weak/copy, readonly/readwrite e assign/retain determinano il comportamento della memoria e la sicurezza dei thread. Key-Value Observing (KVO) è un meccanismo per osservare i cambiamenti delle proprietà, integrato nel runtime: qualsiasi oggetto può sottoscriversi ai cambiamenti delle proprietà di un altro oggetto tramite addObserver.

Domande frequenti

Cos'è la sintassi dei messaggi in Objective-C?

Una chiamata a metodo appare come [object selector:argument]. Il messaggio passa attraverso objc_msgSend, che trova dinamicamente l'implementazione nel runtime. Un selettore è un nome di metodo (@selector(methodName)), non un puntatore a funzione. Ciò consente swizzling e forward invocation.

In cosa differiscono le Categorie dalle Estensioni?

Una Categoria (@interface ClassName (Name)) aggiunge metodi a qualsiasi classe (incluse quelle di sistema) senza ereditarietà. Un'Estensione (@interface ClassName ()) viene dichiarata in un file .m e può aggiungere proprietà e ivar. Una Categoria non può aggiungere ivar, ma un'Estensione sì.

Cosa sono i Blocchi (Blocks) in Objective-C?

I Blocchi sono funzioni anonime con sintassi ^(parametri) { corpo }, che catturano variabili dal contesto. Sono analoghi alle lambda in C++ e alle closure in Swift. Richiedono __weak per prevenire retain cycle durante la cattura di self. Sono usati in UIKit, GCD e Foundation.

Qual è la differenza tra ARC e MRC?

MRC è il conteggio manuale dei riferimenti: il programmatore chiama retain, release, autorelease. ARC è automatico: il compilatore inserisce retain/release basandosi sull'analisi statica. ARC non è GC — gli oggetti vengono rilasciati immediatamente quando il contatore raggiunge zero. ARC supporta i modificatori __weak e __strong.

Si possono usare Objective-C e Swift nello stesso progetto?

Sì, tramite un Bridging Header. Swift vede Objective-C attraverso questa intestazione, Objective-C vede Swift tramite <ProjectName>-Swift.h. Le classi Swift devono ereditare da NSObject ed essere marcate con @objc. Gli struct e gli enum di Swift non sono direttamente visibili a Objective-C.

Riepilogo

  • Objective-C — un superinsieme stretto di C con runtime dinamico e sintassi a messaggi per Cocoa/Cocoa Touch
  • Message passing — chiamate tramite [object method] con dispatch dinamico attraverso objc_msgSend e capacità di swizzling
  • Categorie — aggiunta di metodi a classi esistenti senza ereditarietà, incluse le classi di sistema di Apple
  • Blocchi — funzioni anonime con chiusure, che richiedono __weak per prevenire retain cycle
  • ARC vs MRC — evoluzione dal retain/release manuale al conteggio automatico dei riferimenti tramite il compilatore
  • Bridging Header — meccanismo per far lavorare insieme Swift e Objective-C in un progetto per migrazione graduale
  • Importanza legacy — circa il 35% delle app dell'App Store contiene codice Objective-C che richiede manutenzione

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche