2010-12-27 5 views
14

Ho sempre pensato che non si possa dichiarare una proprietà dell'oggetto in una categoria. Fino a quando il mio partner l'ha fatto nel codice della nostra app, e sembrava funzionare.Da quando è possibile dichiarare le proprietà Objective-C 2.0 in una categoria?

Sono andato su un SO e Google abbuffata per cercare di spiegargli che no, le categorie Objective-C possono essere utilizzate solo per aggiungere metodi, non proprietà. Ho trovato a domande quali:

Ma poi ho trovato this link sul sito di Apple che contiene quanto segue a proposito della dichiarazione @property:

Una dichiarazione di proprietà inizia con la parola chiave @property. @property può apparire ovunque nel metodo elenco dichiarazione trovato nell'interfaccia di una classe. @property può può apparire anche nella dichiarazione di un protocollo o categoria. (Enfasi aggiunta)

So che questo non funziona:

@interface MyClass() 
NSInteger foobar; 
- (void) someCategorizedMethod; 
@end 

Ma questo compila:

@interface MyClass() 
@property NSInteger foobar; 
- (void) someCategorizedMethod; 
@end 

La mia domanda è (a) qual è la migliore pratica qui? e (b) questo è qualcosa di nuovo in Objective-C 2.0, e invece di usare un iVar "reale", semplicemente utilizza lo storage associativo dietro le quinte per farlo funzionare?

risposta

31

Sei sempre stato in grado di dichiarare uno @property in una categoria. Quello che non si poteva fare - e ancora non si può - è dichiarare lo storage per la proprietà nella categoria, né come variabile di istanza, né tramite `@synthesize.

Tuttavia ....

@interface MyClass() è non una categoria. È un'estensione di classe e ha un ruolo decisamente più specifico di una categoria.

Vale a dire, una proroga di classe può essere utilizzato per estendere @interface di una classe, e questo include @properties che possono essere @synthesized (tra cui la sintesi di stoccaggio nel runtime moderna).

Foo.h: 

@interface Foo 
@end 

Foo.m: 

@interface Foo() 
@property int x; 
@end 

@implementation Foo 
@synthesize x; // synthesizes methods & storage 
@end 

si usa semplicemente lo stoccaggio associativa dietro le quinte per fare questo lavoro?

No: è una variabile di istanza reale. Il runtime moderno corregge il fragile problema della classe base.


@interface MyClass() 
NSInteger foobar; 
- (void) someCategorizedMethod; 
@end 

È possibile che questo non funziona (come previsto) perché foobar è, di fatto, una variabile globale.

Se si cambia in:

@interface MyClass() { 
    NSInteger foobar; 
} 
- (void) someCategorizedMethod; 
@end 

Poi lavoreremo con l'ultima release del compilatore LLVM (con le bandiere giuste, come @Joshua indicato in un commento).

+0

Per aggiungere a questo, il suo primo esempio in cui aggiunge un iVar è perfettamente valido in llvm con -Xclang -fobjc-nonfragile-abi2 –

+1

Lo sarebbe se stesse aggiungendo un ivar. In tal caso, sta aggiungendo una variabile statica che non è una variabile di istanza. – bbum

+0

grazie per l'ampia spiegazione. Condividerò questo collegamento con i miei partner di programmazione !! – makdad

1

In generale, le proprietà non sono nulla di diverso dagli altri metodi. Finché l'ivar utilizzato è disponibile nella classe ordinaria , non c'è alcun problema. È solo zucchero sintattico.

Le cose iniziano a diventare più difficili se anche l'ivar viene creato automaticamente, come è possibile in alcune configurazioni.

Il punto principale qui è che la dichiarazione di ivar è indipendente dalla proprietà.

1

Lo stoccaggio assotiative è la soluzione. Dai un'occhiata a questo post.

+0

Grazie per il follow-up - questo è davvero un modo per aggirare questo problema. – makdad