Objective-C deriva la sua sintassi oggetto da Smalltalk. Tutta la sintassi per le operazioni non orientate agli oggetti (incluse variabili primitive, pre-elaborazione, espressioni, dichiarazioni di funzione e chiamate di funzione) sono identiche a quelle di C, mentre la sintassi per le funzionalità orientate agli oggetti è un’implementazione della messaggistica in stile Smalltalk.

MessagesEdit

Il modello Objective-C della programmazione orientata agli oggetti si basa sul passaggio dei messaggi alle istanze degli oggetti. In Objective-C non si chiama un metodo; si invia un messaggio., Questo è diverso dal modello di programmazione in stile Simula utilizzato da C++. La differenza tra questi due concetti sta nel modo in cui viene eseguito il codice a cui fa riferimento il metodo o il nome del messaggio. In un linguaggio in stile Simula, il nome del metodo è nella maggior parte dei casi associato a una sezione di codice nella classe di destinazione dal compilatore. In Smalltalk e Objective-C, la destinazione di un messaggio viene risolta in fase di runtime, con l’oggetto ricevente stesso che interpreta il messaggio., Un metodo è identificato da un selettore o SEL-un identificatore univoco per ogni nome del messaggio, spesso solo una stringa terminata NUL che rappresenta il suo nome-e risolto in un puntatore del metodo C che lo implementa: un IMP. Una conseguenza di ciò è che il sistema di passaggio dei messaggi non ha alcun controllo del tipo. L’oggetto a cui è diretto il messaggio — il ricevitore — non è garantito per rispondere a un messaggio e, in caso contrario, solleva un’eccezione.,

Invio di un messaggio di metodo per l’oggetto a cui punta il puntatore obj richiederebbe il seguente codice in C++:

obj->method(argument);

In Objective-C, questo è scritto come segue:

;

Il “metodo” chiamata viene tradotto dal compilatore per il objc_msgSend(id sé, SEL op …) famiglia di funzioni di runtime. Diverse implementazioni gestiscono aggiunte moderne come super. Nelle famiglie GNU questa funzione è chiamata objc_msg_sendv, ma è stata deprecata a favore di un moderno sistema di ricerca sotto objc_msg_lookup.,

Entrambi gli stili di programmazione hanno i loro punti di forza e di debolezza. La programmazione orientata agli oggetti nello stile Simula (C++) consente l’ereditarietà multipla e un’esecuzione più rapida utilizzando l’associazione in fase di compilazione quando possibile, ma non supporta l’associazione dinamica per impostazione predefinita. Costringe anche tutti i metodi ad avere un’implementazione corrispondente a meno che non siano astratti. La programmazione in stile Smalltalk utilizzata in Objective-C consente ai messaggi di non essere implementati, con il metodo risolto alla sua implementazione in fase di runtime., Ad esempio, un messaggio può essere inviato a una raccolta di oggetti, a cui solo alcuni dovranno rispondere, senza timore di produrre errori di runtime. Il passaggio dei messaggi non richiede inoltre che un oggetto sia definito in fase di compilazione. Un’implementazione è ancora necessaria per il metodo da chiamare nell’oggetto derivato. (Vedere la sezione di battitura dinamica di seguito per ulteriori vantaggi del binding dinamico (tardivo).)

Interfacce e implementazionimodifica

Objective-C richiede che l’interfaccia e l’implementazione di una classe siano in blocchi di codice dichiarati separatamente., Per convenzione, gli sviluppatori posizionano l’interfaccia in un file di intestazione e l’implementazione in un file di codice. I file di intestazione, normalmente suffisso .h, sono simili ai file di intestazione C mentre i file di implementazione (metodo), normalmente suffissi .m, può essere molto simile ai file di codice C.

InterfaceEdit

Questo è analogo alle dichiarazioni di classe utilizzate in altri linguaggi orientati agli oggetti, come C++ o Python.

L’interfaccia di una classe è solitamente definita in un file di intestazione. Una convenzione comune è quella di nominare il file di intestazione dopo il nome della classe, ad esempio Ball.,h conterrebbe l’interfaccia per la palla di classe.

Una dichiarazione di interfaccia assume la forma:

In quanto sopra, i segni più denotano metodi di classe o metodi che possono essere chiamati sulla classe stessa (non su un’istanza), e i segni meno denotano metodi di istanza, che possono essere chiamati solo su una particolare istanza della classe. Anche i metodi di classe non hanno accesso alle variabili di istanza.,

Il codice sopra è approssimativamente equivalente alla seguente interfaccia C++:

Si noti che instanceMethod2With2Parameters:param2_callName: dimostra l’interleaving dei segmenti di selezione con espressioni di argomenti, per i quali non esiste un equivalente diretto in C / C++.

I tipi di ritorno possono essere qualsiasi tipo C standard, un puntatore a un oggetto Objective-C generico, un puntatore a un tipo specifico di oggetto come NSArray *, NSImage * o NSString * o un puntatore alla classe a cui appartiene il metodo (instancetype). Il tipo di ritorno predefinito è l’ID di tipo Objective-C generico.,

Gli argomenti del metodo iniziano con un nome che identifica l’argomento che fa parte del nome del metodo, seguito da due punti seguiti dal tipo di argomento previsto tra parentesi e dal nome dell’argomento. L’etichetta può essere omessa.

Una derivata della definizione dell’interfaccia è la categoria, che consente di aggiungere metodi alle classi esistenti.

ImplementationEdit

L’interfaccia dichiara solo l’interfaccia di classe e non i metodi stessi: il codice effettivo è scritto nel file di implementazione., I file di implementazione (metodo) normalmente hanno l’estensione .m, che originariamente significava “messaggi”.

@implementation classname+ (return_type)classMethod { // implementation}- (return_type)instanceMethod { // implementation}@end

I metodi sono scritti usando le loro dichiarazioni di interfaccia.Confrontando Objective-C e C:

- (int)method:(int)i { return ;}

int function(int i) { return square_root(i);}

La sintassi consente la pseudo-denominazione degli argomenti.

Le rappresentazioni interne di un metodo variano tra le diverse implementazioni di Objective-C., Se myColor è del Colore della classe, il metodo di istanza-changeColorToRed: green: blue: potrebbe essere etichettato internamente _i_Color_changeColorToRed_green_blue. La i deve fare riferimento a un metodo di istanza, con la classe e quindi i nomi dei metodi aggiunti e i due punti modificati in caratteri di sottolineatura. Poiché l’ordine dei parametri fa parte del nome del metodo, non può essere modificato per adattarsi allo stile o all’espressione di codifica come con i parametri con nome vero.

Tuttavia, i nomi interni della funzione vengono raramente utilizzati direttamente. Generalmente, i messaggi vengono convertiti in chiamate di funzione definite nella libreria di runtime Objective-C., Non è necessariamente noto al momento del collegamento quale metodo verrà chiamato perché la classe del ricevitore (l’oggetto a cui viene inviato il messaggio) non deve essere nota fino al runtime.

InstantiationEdit

Una volta scritta una classe Objective-C, può essere istanziata. Questo viene fatto allocando prima un’istanza non inizializzata della classe (un oggetto) e quindi inizializzandola. Un oggetto non è completamente funzionante fino a quando entrambi i passaggi non sono stati completati., Questi passaggi devono essere eseguiti con una riga di codice in modo che non ci sia mai un oggetto allocato che non abbia subito l’inizializzazione (e perché non è saggio mantenere il risultato intermedio poiché -init può restituire un oggetto diverso da quello su cui viene chiamato).,

creazione di un’Istanza, con quello di default senza parametri di inizializzazione:

MyObject *foo = init];

la creazione di istanze con initializer:

MyObject *foo = initWithString:myString];

nel caso In cui non personalizzato inizializzazione viene eseguita, il “nuovo” metodo può essere spesso utilizzato al posto del alloc-init messaggi:

MyObject *foo = ;

Inoltre, alcune classi di implementare un metodo di classe che gli inizializzatori., Come +new, combinano +alloc e -init, ma a differenza di +new, restituiscono un’istanza autoreleased. Alcuni inizializzatori di metodi di classe prendono parametri:

MyObject *foo = ;MyObject *bar = ;

Il messaggio alloc alloca abbastanza memoria per contenere tutte le variabili di istanza per un oggetto, imposta tutte le variabili di istanza su valori zero e trasforma la memoria in un’istanza della classe; in nessun punto durante l’inizializzazione la memoria è un’istanza della superclasse.,

Il messaggio init esegue la configurazione dell’istanza al momento della creazione. Il metodo init è spesso scritto come segue:

- (id)init { self = ; if (self) { // perform initialization of object here } return self;}

Nell’esempio precedente, notare il tipo di ritorno id. Questo tipo sta per “puntatore a qualsiasi oggetto” in Objective-C (Vedere la sezione di digitazione dinamica).

Il modello di inizializzazione viene utilizzato per assicurare che l’oggetto sia inizializzato correttamente dalla sua superclasse prima che il metodo init esegua la sua inizializzazione., Esegue le seguenti azioni:

  1. self = Invia all’istanza superclasse un messaggio init e assegna il risultato a self (puntatore all’oggetto corrente).
  2. if (self)Controlla se il puntatore dell’oggetto restituito è valido prima di eseguire qualsiasi inizializzazione.
  3. return self restituisce il valore di self al chiamante.

Un puntatore oggetto non valido ha il valore nil; istruzioni condizionali come “if” trattano nil come un puntatore null, quindi il codice di inizializzazione non verrà eseguito se restituito nil., Se si verifica un errore nell’inizializzazione, il metodo init dovrebbe eseguire qualsiasi pulizia necessaria, incluso l’invio di un messaggio “release” a self e restituire nil per indicare che l’inizializzazione non è riuscita. Qualsiasi controllo di tali errori deve essere eseguito solo dopo aver chiamato l’inizializzazione della superclasse per garantire che la distruzione dell’oggetto venga eseguita correttamente.

Se una classe ha più di un metodo di inizializzazione, solo uno di essi (l ‘ “inizializzatore designato”) deve seguire questo modello; altri dovrebbero chiamare l’inizializzatore designato invece dell’inizializzatore superclasse.,

ProtocolsEdit

In altri linguaggi di programmazione, questi sono chiamati “interfacce”.

Objective-C è stato esteso a NeXT per introdurre il concetto di ereditarietà multipla delle specifiche, ma non l’implementazione, attraverso l’introduzione di protocolli. Questo è un modello realizzabile sia come classe base ereditata multipla astratta in C++, sia come “interfaccia” (come in Java e C#). Objective-C fa uso di protocolli ad hoc chiamati protocolli informali e protocolli imposti dal compilatore chiamati protocolli formali.,

Un protocollo informale è un elenco di metodi che una classe può scegliere di implementare. È specificato nella documentazione, poiché non ha presenza nella lingua. I protocolli informali sono implementati come categoria (vedi sotto) su NSObject e spesso includono metodi opzionali, che, se implementati, possono modificare il comportamento di una classe. Ad esempio, una classe di campo di testo potrebbe avere un delegato che implementa un protocollo informale con un metodo opzionale per eseguire il completamento automatico del testo digitato dall’utente., Il campo di testo rileva se il delegato implementa tale metodo (tramite reflection) e, in tal caso, chiama il metodo del delegato per supportare la funzionalità di completamento automatico.

Un protocollo formale è simile a un’interfaccia in Java, C# e Ada 2005. È un elenco di metodi che qualsiasi classe può dichiarare di implementare. Le versioni di Objective-C prima della 2.0 richiedevano che una classe implementasse tutti i metodi in un protocollo che si dichiara di adottare; il compilatore emetterà un errore se la classe non implementa tutti i metodi dai suoi protocolli dichiarati. Obiettivo C 2.,0 aggiunto il supporto per contrassegnare determinati metodi in un protocollo opzionale e il compilatore non applicherà l’implementazione dei metodi opzionali.

Una classe deve essere dichiarata per implementare quel protocollo per essere detto conforme ad esso. Questo è rilevabile in fase di esecuzione. I protocolli formali non possono fornire alcuna implementazione; semplicemente assicurano ai chiamanti che le classi conformi al protocollo forniranno implementazioni. Nella libreria NeXT/Apple, i protocolli vengono spesso utilizzati dal sistema Distributed Objects per rappresentare le capacità di un oggetto in esecuzione su un sistema remoto.,

La sintassi

@protocol NSLocking- (void)lock;- (void)unlock;@end

indica che esiste l’idea astratta del blocco. Affermando nella definizione della classe che il protocollo è implementato,

@interface NSLock : NSObject <NSLocking>// ...@end

le istanze di NSLock affermano che forniranno un’implementazione per i due metodi di istanza.

Dynamic typingEdit

Objective-C, come Smalltalk, può usare dynamic typing: a un oggetto può essere inviato un messaggio che non è specificato nella sua interfaccia., Ciò può consentire una maggiore flessibilità, in quanto consente a un oggetto di “catturare” un messaggio e inviare il messaggio a un oggetto diverso che può rispondere al messaggio in modo appropriato, o allo stesso modo inviare il messaggio a un altro oggetto. Questo comportamento è noto come inoltro dei messaggi o delega (vedi sotto). In alternativa, è possibile utilizzare un gestore di errori nel caso in cui il messaggio non possa essere inoltrato. Se un oggetto non inoltra un messaggio, non risponde o non gestisce un errore, il sistema genererà un’eccezione di runtime., Se i messaggi vengono inviati a nil (il puntatore dell’oggetto nullo), verranno ignorati silenziosamente o genereranno un’eccezione generica, a seconda delle opzioni del compilatore.

Le informazioni di battitura statica possono anche essere aggiunte facoltativamente alle variabili. Questa informazione viene quindi verificata in fase di compilazione. Nelle seguenti quattro dichiarazioni, vengono fornite informazioni sul tipo sempre più specifiche. Le istruzioni sono equivalenti in fase di esecuzione, ma le informazioni aggiuntive consentono al compilatore di avvisare il programmatore se l’argomento passato non corrisponde al tipo specificato.,

- (void)setMyValue:(id)foo;

Nell’istruzione precedente, foo può essere di qualsiasi classe.

- (void)setMyValue:(id<NSCopying>)foo;

Nell’istruzione precedente, foo può essere un’istanza di qualsiasi classe conforme al protocolloNSCopying.

- (void)setMyValue:(NSNumber *)foo;

Nell’istruzione precedente, foo deve essere un’istanza della classe NSNumber.

- (void)setMyValue:(NSNumber<NSCopying> *)foo;

Nell’istruzione precedente, foo deve essere un’istanza della classe NSNumber e deve essere conforme al protocolloNSCopying.,

In Objective-C, tutti gli oggetti sono rappresentati come puntatori e l’inizializzazione statica non è consentita. L’oggetto più semplice è il tipo a cui punta id (objc_obj*), che ha solo un puntatore isa che descrive la sua classe. Altri tipi da C, come i valori e le strutture, sono invariati perché non fanno parte del sistema di oggetti. Questa decisione differisce dal modello a oggetti C++, in cui le strutture e le classi sono unite.

ForwardingEdit

Objective-C consente l’invio di un messaggio a un oggetto che potrebbe non rispondere., Invece di rispondere o semplicemente rilasciare il messaggio, un oggetto può inoltrare il messaggio a un oggetto che può rispondere. L’inoltro può essere utilizzato per semplificare l’implementazione di determinati modelli di progettazione, come il modello observer o il modello proxy.

Il runtime Objective-C specifica una coppia di metodi in Object

Un oggetto che desidera implementare l’inoltro deve solo sovrascrivere il metodo di inoltro con un nuovo metodo per definire il comportamento di inoltro. Il metodo di azione performv:: non deve essere sovrascritto, poiché questo metodo esegue semplicemente un’azione basata sul selettore e sugli argomenti., Si noti il tipoSEL, che è il tipo di messaggi in Objective-C.

Nota: in OpenStep, Cocoa e GNUstep, i framework comunemente usati di Objective-C, non si utilizza la classe Object. Il metodo – (void)forwardInvocation: (NSInvocation *)anInvocation della classe NSObject viene utilizzato per eseguire l’inoltro.

ExampleEdit

Ecco un esempio di un programma che dimostra le basi dell’inoltro.

Spedizioniere.h Spedizioniere.m Destinatario.h

#import <objc/Object.h>// A simple Recipient object.@interface Recipient : Object- (id)hello;@end

Destinatario.m

#import "Recipient.h"@implementation Recipient- (id)hello { printf("Recipient says hello!\n"); return self;}@end

principale.,m

NotesEdit

Quando compilato utilizzando gcc, il compilatore segnala:

Il compilatore sta segnalando il punto fatto in precedenza, che lo spedizioniere non risponde ai messaggi hello. In questa circostanza, è sicuro ignorare l’avviso poiché l’inoltro è stato implementato. L’esecuzione del programma produce questo output:

$ ./a.outRecipient says hello!

Categorieedit

Durante la progettazione di Objective-C, una delle principali preoccupazioni era la manutenibilità di grandi basi di codice., L’esperienza del mondo della programmazione strutturata ha dimostrato che uno dei modi principali per migliorare il codice era scomporlo in pezzi più piccoli. Objective-C ha preso in prestito ed esteso il concetto di categorie dalle implementazioni Smalltalk per aiutare con questo processo.

Inoltre, i metodi all’interno di una categoria vengono aggiunti a una classe in fase di esecuzione. Pertanto, le categorie consentono al programmatore di aggiungere metodi a una classe esistente – una classe aperta-senza la necessità di ricompilare quella classe o persino di avere accesso al suo codice sorgente., Ad esempio, se un sistema non contiene un correttore ortografico nella sua implementazione Stringa, potrebbe essere aggiunto senza modificare il codice sorgente della stringa.

I metodi all’interno delle categorie diventano indistinguibili dai metodi di una classe quando viene eseguito il programma. Una categoria ha pieno accesso a tutte le variabili di istanza all’interno della classe, comprese le variabili private.

Se una categoria dichiara un metodo con la stessa firma del metodo di un metodo esistente in una classe, viene adottato il metodo della categoria. Pertanto le categorie possono non solo aggiungere metodi a una classe, ma anche sostituire i metodi esistenti., Questa funzione può essere utilizzata per correggere i bug in altre classi riscrivendo i loro metodi o per causare una modifica globale al comportamento di una classe all’interno di un programma. Se due categorie hanno metodi con lo stesso nome ma firme di metodi diverse, non è definito quale metodo di categoria viene adottato.

Altre lingue hanno tentato di aggiungere questa funzione in vari modi. TOM ha preso il sistema Objective-C un ulteriore passo avanti e ha permesso l’aggiunta di variabili anche. Altri linguaggi hanno invece utilizzato soluzioni basate su prototipi, il più notevole è Self.

Il C # e Visual Basic.,I linguaggi NET implementano funzionalità superficialmente simili sotto forma di metodi di estensione, ma questi non hanno accesso alle variabili private della classe. Ruby e molti altri linguaggi di programmazione dinamici si riferiscono alla tecnica come “patch monkey”.

Logtalk implementa un concetto di categorie (come entità di prima classe) che sussume la funzionalità delle categorie Objective-C (Le categorie Logtalk possono anche essere utilizzate come unità di composizione a grana fine quando si definiscono, ad esempio, nuove classi o prototipi; in particolare, una categoria Logtalk può essere praticamente importata da qualsiasi numero di classi e prototipi).,

Esempio uso di categoriesEdit

Questo esempio crea una classe intera, definendo prima una classe di base con implementati solo metodi di accesso e aggiungendo due categorie, Aritmetica e Visualizzazione, che estendono la classe di base. Mentre le categorie possono accedere ai membri di dati privati della classe base, è spesso buona norma accedere a questi membri di dati privati tramite i metodi di accesso, che aiutano a mantenere le categorie più indipendenti dalla classe base. L’implementazione di tali accessor è un uso tipico delle categorie. Un altro è usare le categorie per aggiungere metodi alla classe base., Tuttavia, non è considerata una buona pratica utilizzare le categorie per l’override della sottoclasse, noto anche come patch di scimmie. I protocolli informali sono implementati come categoria nella classe NSObject di base. Per convenzione, i file contenenti categorie che estendono le classi base assumeranno il nome BaseClass + ExtensionClass.h.

Intero.h

#import <objc/Object.h>@interface Integer : Object { int integer;}- (int)integer;- (id)integer:(int)_integer;@end

Integer.m Intero + Aritmetica.h

#import "Integer.h"@interface Integer (Arithmetic)- (id) add: (Integer *) addend;- (id) sub: (Integer *) subtrahend;@end

Intero+Aritmetica.m Intero + Display.h

#import "Integer.h"@interface Integer (Display)- (id) showstars;- (id) showint;@end

Integer+Display.m principale.,m

NotesEdit

La compilazione viene eseguita, ad esempio, da:

gcc -x objective-c main.m Integer.m Integer+Arithmetic.m Integer+Display.m -lobjc

Si può sperimentare tralasciando il #import “Integer+Arithmetic.h ” e linee e omettendo intero + aritmetica.m nella compilazione. Il programma continuerà a funzionare. Ciò significa che è possibile mix-and-match aggiunto categorie, se necessario; se una categoria non ha bisogno di avere una certa capacità, può semplicemente non essere compilare in.

PosingEdit

Objective-C consente a una classe di sostituire completamente un’altra classe all’interno di un programma. La classe di sostituzione si dice “posa come” la classe di destinazione.,

La classe posing è stata dichiarata deprecata con Mac OS X v10.5 e non è disponibile nel runtime a 64 bit. Funzionalità simili possono essere ottenute utilizzando il metodo swizzling in categorie, che scambia l’implementazione di un metodo con un’altra che ha la stessa firma.

Per le versioni che supportano ancora la posa, tutti i messaggi inviati alla classe target vengono invece ricevuti dalla classe posing. Ci sono diverse restrizioni:

  • Una classe può rappresentare solo una delle sue superclassi dirette o indirette.,
  • La classe posing non deve definire nuove variabili di istanza assenti dalla classe target (sebbene possa definire o sovrascrivere i metodi).
  • La classe target potrebbe non aver ricevuto alcun messaggio prima della posa.

La posa, analogamente alle categorie, consente l’aumento globale delle classi esistenti. Posing consente due funzionalità assenti dalle categorie:

  • Una classe posing può chiamare metodi sovrascritti tramite super, incorporando così l’implementazione della classe target.
  • Una classe in posa può sovrascrivere i metodi definiti nelle categorie.,

Ad esempio,

Questo intercetta ogni invocazione di setMainMenu a NSApplication.

#importEdit

Nel linguaggio C, la direttiva di pre-compilazione#include fa sì che il contenuto di un file venga sempre inserito nella sorgente in quel punto. Objective-C ha la direttiva#import, equivalente tranne che ogni file è incluso solo una volta per unità di compilazione, evitando la necessità di includere guardie.

Compilazione Linux gccmodifica

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *