giovedì 29 aprile 2010

Guida Objective-C in Italiano - Parte 7 - Categorie ed Estensioni


Eccoci alla settima parte della Guida alla programmazione in Objective-C, oggi parleremo di Categorie ed Estensioni.

Questo post è una traduzione in italiano della Guida all'Objective C, presente sul sito developer.apple.com a questo link. L'Objective C è il linguaggio di programmazione per creare applicazioni per iPhone. Questo articolo può interessare a tutti gli sviluppatori che vogliono imparare le basi di questo linguaggio che è il fondamento per programmare nuove applicazioni per Mac Os X, iPhone ed iPad.


Categorie ed Estensioni

Una categoria ti permette di aggiungere metodi ad una classe esitente - anche ad una di cui no hai il codice sorgente. Questa è una caratteristica molto potente che ti permette di estendere le funzionalità di una classe esistente senza crearne una sottoclasse. Usando le categorie, puoi anche dividere l'implementazione delle tue classi tra molti files. Le estensioni delle classi sono simili, ma permettono ad API aggiuntive richieste di essere dichiarate per una classe in locazioni diverse dal blocco @interface della classe primaria.

Aggiungere Metodi a Classi

Puoi aggiungere metodi ad una classe dichiarandoli in un file interfaccia sotto un nome di categoria e definendoli in un file implementazione sotto lo stesso nome. Il nome di categoria indica che i metodi sono delle aggiunte ad una classe dichiarata da qualche altra parte, non una nuova classe. non pouoi, comunque usare una categoria per aggiungere variabili di istanza ad una classe.

I metodi che la categoria aggiunge diventano parte del tipo della classe. Ad esempio i metodi aggiunti alla classe NSArray in una categoria sono tra i metodi che il compilatore si aspetta di trovare nel repertorio dei metodi di un'istanza della classe NSArray. I metodi aggiunti alla classe NSArray in una sottoclasse non sono inclusi nel tipo NSArray. (Questo importa solo per oggetti tipati staticamente dato che lo static typing è l'unico modo per il compilatore di conoscere la classe di un oggetto).

I metodi di Categoria possono fare qualunque cosa che possono fare i metodi definiti nella classe. A runtime non c'è differenza. I metodi che la categoria aggiunge alla classe sono ereditati da tutte le sottoclassi, proprio come gli altri metodi.

La dichiarazione di un'interfaccia di categoria appare molto come una dichiarazione di interfaccia di classe - tranne che il nome di categoria è elencato tra parentesi dopo il nome di classe e la superclasse non è menzionata. A meno che i suoi metodi non accedano ad alcuna variabile di istanza della classe, la categoria deve importare il file interfaccia della classe che estende:
#import "ClassName.h"



@interface ClassName ( CategoryName )

// method declarations

@end

L'implementazione, come al solito, importa la sua propria interfaccia. Una convenzione comune per i nomi è che il nome del file di base della categoria è il nome della classe che la categoria estende seguito da un "+" seguito dal nome della categoria. Un'implementazione di categoria (in un file nominato NomeClasse+NomeCategoria.m) potrebbe quindi apparire così:
#import "ClassName+CategoryName.h"



@implementation ClassName ( CategoryName )

// method definitions

@end

Nota che una categoria non può dichiarare variabil idi istanza aggiuntive per la classe; include solo metodi. Comnque, tutte le variabili di istanza entro lo scope della classe sono anche nello scope della categoria. questo include tutte le variabili di istanza dichiarate dalla classe, anche quelle dichiarate @private.

Non c'è limite al numero di categorie che puoi aggiungere ad una classe, ma ogni nome di categoria deve essere diverso, ed ognuno dovrebbe dichiarare e definire un insieme diverso di metodi.

Come Usare le Categorie

Ci sono tanti modi di usare le categorie:
  • Per estendere classi definite da altrei implementatori. Ad esempio, se puoi aggiungre metodi alle classi definite nel frameworks Cocoa. I metodi aggiunti sono ereditati dalle sottoclassi e sono indistinguibili a runtime dai metodi originali della classe.
  • Come alternativa ad una sottoclasse. Piuttosto che definire una sottoclasse per estendere una classe esistente, attraverso una categoria puoi aggiungeremetodi alla classe direttamente. Ad esempio, puoi aggiungere categorie a NSArray e altre classi Cocoa. Come nel caso di una sottoclasse, non hai bisogno del codice sorgente della classe che stai estendendo.
  • Per distribuire l'implementazione di una nuova classe in files sorgenti separati. Ad esempio, puoi raggruppare i metodi di una classe grande in diverse categorie e mettere ogni categoria in un file diverso. Quando sono usate in questo modo, le categorie possono beneficiare del processo di sviluppo in un vari modi - Esse:
    • Forniscono un semplice modo di raggruppare metodi correlati. Metodi simili definiti in classi diverse possono essere messi insieme nello stesso file sorgente.
    • Semplifica la gestione di una classe grande quando molti sviluppatori contribuiscono alla sua definizione.
    • Ti permette di raggiungere alcuni dei benefici della compilazione incrementale per una classe molto grande.
    • Può aiutare a migliorare la località delle referenze per metodi comunemente usati.
    • Ti Abilita a configurare una classe diversamente per applicazioni separate, senza dover mantenere diverse versioni dello stesso codice.

Sebbene il linguaggio ti permette di usare una categoria per sovrascrivere i metodi che la classe eredita, o anche i metodi dichiarati nell'interfaccia della classe, è fortemente sconsigliato l'uso di questa funzionalità. Una categoria non è una sostituta per una sottoclasse. Ci sono molte imperfezioni significanti:
  • Quando una categoria sovrascrive un metodo ereditato, il metodo nella categoria può, come è solito, invocare l'implementazione ereditata tramite un messaggio a super. Comunque, se una categoria sovrascrive un metodo che esiste già nella classe della categoria, non c'è modo per invocare l'implementazione originale.
  • Una categoria non può sovrascrivere con affidabilità i metodi dichiarati in un altra categoria della stessa classe. Questo problema è particolarmente significante dato che molte delle classi Cocoa sono implementate usando le categorie. Un metodo basato su framework che provi a sovrascrivere potrebbe essere stato implementato in una categoria, e quindi non è definito quale implementazione ha la precedenza.
  • La presena di alcuni metodi potrebbe causare cambi dei comportamenti tra tutti i frameworks. Ad esempio, se aggiungi un'implementazione di windowWillClose: a NSObject, questo causerà che tutte le finestre delegate risponderanno a quel metodo e potrebbero modificare il comportamento di tutte le istanze di NSWindow. Questo potrebbe causare cambiamenti misteriosi nel comportamento e potrebbe condurre a crashes.

Categorie della Classe Radice

Una categoria può aggiungere metodi ad ogni classe, incluso nella classe radice. I metodi aggiunti a NSObject diventano disponibili a tutte le classi che sono collegate al tuo codice. Mentre questo può essere utile a volte, può anche essere abbastanza pericoloso. Sebbene potrebbe sembrare che le modifiche che le categorie fanno siano ben capite e di impatto limitato, l'ereditarietà gli da un ampio scope. Potresti fare dei cambi non intenzionali a classi non viste; potresti non conoscere tutte le conseguenze di ciò che stai facendo. Inoltre, gli altri che non sono a conoscenza dei tuoi cambi non capiranno cosa stanno facendo.

In aggiunta, ci sono altre due considerazioni da tenere a mente quando si implementano metodi per la classe radice:
  • Messaggi a super sono invalidi (non c'è la superclasse).
  • Gli oggetti di classe possono eseguire metodi di istanza definiti nella classe radice.
Normalmente gli oggetti di classe possono eseguire solo metodi di classe. Ma i metodi di istanza definiti nella classe radice sono un caso speciale. Essi definiscono un'interfaccia al sistema di runtime che tutti gli oggetti ereditano. Gli oggetti di classe sono oggetti full-fledged e devono condividere la stessa interfaccia.

Questa caratteristica significa che hai bisogno di tener conto della possibilità che un metodo di istanza che definisci in una categoria della classe NSObject potrebbe essere eseguito non solo da istanze ma da anche da oggetti di classe. Ad esempio, nel corpo del metodo, self potrebbe significare un oggetto di classe così come un'istanza.

Estensioni

Le estensioni di classi sono come categorie "anonime", tranne che i metodi che dichiarano devono essere implementati nel blocco principale @implementation per la classe corrispondente.

È comune per una classe avere un'API pubblicamente dichiarata e poi avere API aggiuntiva dichiarata privatamente per solo uso della classe o del framework dentro il quale risiede la classe. Puoi dichiarare tale API in una categoria (o in più di una categoria) in un file header privato o in un file di implementazione come descritto sopra. Questo funziona, ma il compilatore non può verificare che tutti i metodi dichiarati siano implementati.

Ad esempio, il compilatore compilerà senza errori le seguenti dichiarazioni e implementazioni:
@interface MyObject : NSObject

{

NSNumber *number;

}

- (NSNumber *)number;

@end



@interface MyObject (Setter)

- (void)setNumber:(NSNumber *)newNumber;

@end





@implementation MyObject



- (NSNumber *)number {

return number;

}

@end

Nota che non c'è implementazione del metodo setNumber:. Se è invocato a runtime genererà un errore.

Le estensioni di classe ti permettono di dichiarare API aggiuntive richieste per una classe in locazioni diverse da dentro al blocco primario @interface della classe, come illustrato nel seguente esempio:
@interface MyObject : NSObject

{

NSNumber *number;

}

- (NSNumber *)number;

@end



@interface MyObject ()

- (void)setNumber:(NSNumber *)newNumber;

@end





@implementation MyObject



- (NSNumber *)number {

return number;

}

- (void)setNumber:(NSNumber *)newNumber {

number = newNumber;

}

@end

Nota che in questo caso:
  • Non è dato un nome nelle parentesi nel secondo blocco @interface;
  • L'implementazione del metodo setNumber: appare dentro al blocco @implementation princpiale della classe.
L'implementazione del metodo setNumber. deve apparire dentro al blocco @implementation princpale della classe (non poui implementarlo in una categoria). Se questo non è il caso, il compilatore emetterà un warning avvisando che non può trovare una definizione di metodo per setNumber:.

Fine Settima Parte

Finisce qui il settimo articolo di questa Guida dedicato alle Categorie e Estensioni del linguaggio di programmazione Objective-C. Spero col tempo di realizzare un'utile manuale disponibile a tutti. Il prossimo post di questa guida, tratterà i Riferimenti Associativi, un utile strumento per simulare l'aggiunta di variabili di istanza di un oggetto ad una classe esistente. Segnalatemi eventuali errori, o commentate l'articolo se l'avete trovato utile, anche per incentivarmi a continuare a pubblicare le mie traduzioni. Iscrivetevi ai feed del blog per essere sempre aggiornati automaticamente ogni volta che sono disponibili nuovi contenuti. Nella barra laterale del blog potete trovare l'elenco di tutti gli articoli di questa guida.

Nessun commento:

Posta un commento

Related Posts with Thumbnails