2015-08-08 9 views
6

Ho imparato Objective-C per un po '. Da quanto ho appreso, so che quando si dichiara una variabile all'interno di @interface nel file .h, è possibile accedere alla variabile pubblicamente (simile a una variabile pubblica in java).Differenza tra la dichiarazione di una variabile in @Implementation e @Interface nel file .m

@interface MyObject 

@property NSInteger intData; 

@end 

Ma quando si dichiara che all'interno @interface nel file .m . È possibile accedervi solo all'interno del file .m solo in @implementation, a meno che non fornisca un getter e un setter per questo.

@interface MyObject() 

@property NSInteger intData; 

@end 

Ma anche notato un altro modo di dichiarazione di una variabile, che si dichiara sotto @implementation

@implementation 

NSInteger intData; 

@end 

e vedo che funziona allo stesso modo di dichiarare sotto @interface con @property in .m file

Non capisco la differenza tra i due (dichiarando in @implementation e in @interface (nel file .m).

Ho già cercato lo stack di questo, ma tutti stavano parlando della differenza tra @implementation e @interface (nel file .h). Quindi pensa che questo non sia un duplicato.

+2

Il 'NSInteger' dichiarato all'interno dell'interfaccia' @ 'è una variabile globale. È anche solo una variabile, senza alcuna trappola di una proprietà (metodi di accesso, KVC, ecc.). – Rob

risposta

4

Prima di tutto, non stai dichiarando una variabile; stai dichiarando una proprietà. Una proprietà è supportata da una variabile di istanza, ma aggiunge anche dei metodi. Ecco una spiegazione dei luoghi di mettere variabili:

@interface MyClass : NSObject { 
    NSInteger i ; 
} 
@end 

Questo è un posto per mettere una variabile di istanza sulla tua classe. È accessibile solo con metodi della tua classe e categorie. (Sidenote: Può essere reso accessibile dall'esterno, ma non è una pratica consigliata)

altro esempio:

@interface MyClass : NSObject 
@end 

@implementation MyClass { 
    NSInteger i ; 
} 
@end 

Questa è anche una variabile di istanza, ma è solo raggiungibile con metodi scritte all'interno quel blocco . (Sidenote: si può accedere scavando attraverso la definizione di classe, ma che non è un raccomandato (o comune) pratica)

altro esempio:

@interface MyClass : NSObject 
@property NSInteger i ; 
@end 

è lo stesso:

@interface MyClass : NSObject { 
    NSInteger _i ; // you are not allowed to access it by this variable 
} 
- (NSInteger) i ; 
- (void) setI:(NSInteger)value ; 
@end 

Questa è una proprietà che le persone possono ottenere e impostare.Si utilizza tale variabile nei vostri metodi o in altri metodi come:

NSLog (@"The value is %i" , self.i) ; // if it's your instance method 
NSLog (@"The value is %i" , object.i) ; // if it's object's instance method 

Un altro esempio:

@interface MyClass : NSObject { 
    NSInteger i ; 
} 
@property NSInteger i ; 
@end 
@implementation MyClass 
@synthesize i ; // Causes the property to line up with the ivar by the same name. 
@end 

è la stessa:

@interface MyClass : NSObject { 
    NSInteger i ; // you ARE allowed to use this since you defined it 
} 
- (NSInteger) i ; 
- (void) setI:(NSInteger)value ; 
@end 

Qui, è possibile utilizzare il getter/metodi setter o la variabile di istanza stessa. Tuttavia, dovresti generalmente usare i metodi perché tu [implicitamente] li hai dichiarati atomici in modo da avere la sincronizzazione dei thread. Se si vuole rendere non lo fanno threading (e accelerarlo, fino a quando non avete intenzione di usarlo in un ambiente multi-threaded):

@property (nonatomic) NSInteger i ; 
@property (nonatomic,readonly) NSInteger i ; // only makes a getter method 

Mi consiglia di evitare questo per un mentre usi le proprietà diritte perché ti aiuterà a evitare molti errori comuni. A meno che non profili il tuo programma e determini che questa è una causa di una perdita di prestazioni, dovresti probabilmente semplicemente usare le proprietà.

Un altro esempio:

@interface MyClass : NSObject 
@end 

@implementation MyClass 
NSInteger i ; 
@end 

Questo è NON una variabile di istanza. È una variabile globale che è stata scritta all'interno dello scope @implementation.

Vedere sopra per come trasformarlo in una variabile di istanza (ovvero inserirla tra parentesi).

Una nota di più:

Dichiarare una proprietà come questa:

@interface MyClass() 
@property NSInteger i ; 
@end 

non rende privata. Tuttavia, è nascosto in un file a cui le persone generalmente non possono accedere in modo che il compilatore non sappia che esiste una proprietà.

Altre funzioni altrove nel codice può ancora chiamare:

[yourObject i] ; 

per ottenere il valore di quella proprietà - ma devono sapere che è lì prima.

Addendum per rispondere a una domanda nei commenti:

proprietà sono, per impostazione predefinita, atomico. Non segue necessariamente la definizione rigorosa di atomico (questa è una lattina di worm che ti suggerisco di non guardare in questo momento), ma ha lo stesso effetto: i thread sono garantiti per vedere un valore completo e aggiornato , indipendentemente da quando un altro thread scrive su di esso. Lo fa in genere questo quando si sintetizza i metodi getter/setter:

- (NSInteger) i { 
    @synchronized(self) { 
     return i ; 
    } 
} 
- (void) setI:(NSInteger)value { 
    @synchronized(self) { 
     i = value ; 
    } 
} 

Se invece si specifica nonatomic, sarà sintetizzare questi:

- (NSInteger) i { 
    return i ; 
} 
- (void) setI:(NSInteger)value { 
    i = value ; 
} 

Se la vostra proprietà è atomic, allora non si dovrebbe mai accedere direttamente a Ivar. Farlo viola la protezione del threading che hai dato all'inizio.(Sidenote: ci sono casi in cui è possibile, ma aspettare fino a quando si diventa più familiarità con filettatura/sincronizzazione prima di tentare di esso.)

+0

Prima di tutto, grazie per aver fatto un tale sforzo per rispondere alla mia domanda. Voglio solo chiarire alcune cose nella tua risposta. Nella tua spiegazione, la parte che inizia con "Qui, puoi usare i metodi getter e setter ...", hai detto che "dovresti generalmente usare i metodi perché tu [implicitamente] li hai dichiarati atomici". Uhm, intendevi "nonatomico"? perché il tuo esempio dopo ciò afferma @property (nonatomic) NSInteger i. Sono un po 'confuso su quella parte. –

+1

@EpicNinja - Ho aggiunto alcune cose extra in fondo che descrivono cosa stanno facendo 'atomic' e' nonatomic'. – iAdjunct

+2

Alcuni problemi con questa risposta. 1) Non utilizzare il 1 ° esempio di codice. Non vi è alcun motivo per dichiarare ivars privati ​​nel file di intestazione pubblico. 2) Il secondo esempio di codice dichiara un ivar privato. La tua affermazione "accessibile con metodi scritti all'interno di quel blocco" è un po 'confusa. È possibile accedere a tale variabile con qualsiasi metodo di istanza della classe. 3) Si dovrebbe ricordare che la dichiarazione delle variabili globali all'interno della linea '@ implementation' può essere trasformata in un ivar corretto semplicemente usando le parentesi graffe. – rmaddy

4

Quando si dichiara la proprietà nel @interface MyObject(){} si dichiara in quello che è chiamato un annonymous o categoria. Poiché è dichiarato nel file .m, è visibile solo all'interno di quel file (nessun'altra classe può vederlo). Tuttavia, avresti potuto dichiarare questa categoria nel tuo file .h, nel qual caso sarebbe visibile ad altre classi.

Dichiarare NSInteger intData all'interno della @implementation parte della classe non sta effettivamente dichiarando una variabile di istanza. Sta dichiarando una variabile globale, il che significa che esiste un'unica istanza condivisa dall'intera applicazione o, se si desidera osservarla in questo modo, tutte le istanze della classe (poiché è l'unica a essere consapevole di questa variabile globale).

+3

"chiamato una [anonima] o categoria" ... O una "estensione di classe" (consultare [Estensioni di classe estendere l'implementazione interna] (https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual /ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html#//apple_ref/doc/uid/TP40011210-CH6-SW3)). – Rob

+1

La variabile globale può essere trasformata in un ivar semplicemente aggiungendo parentesi graffe. – rmaddy

Problemi correlati