2009-06-22 11 views
7

qual è la differenza tra una funzione C (statica o meno) dichiarata all'interno o all'esterno del blocco di implementazione (@implementation ... @end) di una classe Objective-C?Obj-C: funzioni C dichiarate all'interno o all'esterno del blocco @implementation, qual è la differenza?

è questo particolarmente vero ?:

Se avete bisogno di colpire all'interno dell'oggetto direttamente, è possibile inserire questa funzione all'interno del blocco @implementation della classe, e quindi è possibile accedere alle variabili di istanza con l'operatore freccia C. Ma è un po 'cattivo, quindi per preservare la tua Purezza di Essenza dovresti usare le chiamate di metodo sul tuo oggetto. Fine del sermone. Ecco il male:

@implementation OblateSphereoid 

void drawEggThunk (DrawingContext *context, Rect areaToDraw, void *userData) 
{ 
BWOblateSphereoid *dealie = (BWOblateSphereoid *)userData; 
dealie->_frognatz = [NSColor plaidColor]; 
// and more stuff. 
} // drawEggThunk 

... 
@end // OblateSphereoid 

posso accedere alle variabili della mia classe delle istanze all'interno di funzioni (dichiarati nella stessa classe) in questo modo?

+0

Inevitato per essere una domanda interessante (anche se forse pratica molto negativa) Solo per curiosità, puoi chiamare drawEggThunk solo dalla tua classe? –

+0

non posso, la funzione è una funzione di callback chiamata da un sottosistema C, come potete vedere io uso * userData per passare un riferimento a self quando sono configurate le callback. – jlpiedrahita

risposta

2

Mentre questo è legale, non capisco perché è richiesto nel tipo di caso che hai descritto (ed è una brutta soluzione). Perché non si può chiamare:

[dealie setFrognatz:[NSColor plaidColor]]; 

Se non si dispone di solito forniscono un -setFrognatz:, basta fare un metodo privato dichiarando all'interno del .m, ma soprattutto la definizione di funzione. (In realtà non importa se è nel @implementation blocco in questo caso.)

@interface BWOblateSphereoid() 
- (void)setFrognatz:(NSColor *)acolor 
@end 

@implementation OblateSphereoid 

void drawEggThunk (DrawingContext *context, Rect areaToDraw, void *userData) 
{ 
    BWOblateSphereoid *dealie = (BWOblateSphereoid *)userData; 
    [dealie setFrognatz:[NSColor plaidColor]]; 
    // and more stuff. 
} // drawEggThunk 

... 
@end // OblateSphereoid 

Ci sono alcuni posti in cui -> notazione può essere utile. Il più critico è nell'implementazione di -copyWithZone: dove può essere absolutely required (un requisito che enfatizza davvero il motivo per cui odio qualsiasi codice ObjC che funzioni con memoria raw come NSCopyObject()). Ma io consiglio contro lo -> nella maggior parte dei casi per gli stessi motivi che raccomando sempre agli utenti. Anche nel caso in cui è necessario passare un ivar facendo riferimento a una funzione C (un altro uso comune di ->), preferisco utilizzare un temporaneo e quindi assegnarlo in seguito.

ritengo il fatto che non sono Ivars @private di default tratta di un problema in objC .... ho messo @private nella parte superiore di ogni @interface blocco ed ho evitato diversi bug fastidiosi che modo.

BTW, la vostra soluzione come scritta potrebbe perdere uno NSColor. Forse lo è, forse non lo è, ma una Accessor sarebbe certa.

+0

Il metodo "privato" è la risposta per il problema di fondo (accesso agli ivar all'interno delle funzioni senza interruzioni di interruzione) :) ma ... c'è qualche differenza tra le funzioni all'interno e all'esterno di @impementation? – jlpiedrahita

+0

a proposito, objc ivars sono di default @ protetti, questo è l'ambito perfetto: visibile per la classe stessa e le sottoclassi e nascosto per tutto il resto. – jlpiedrahita

+0

Non c'è differenza tra l'implementazione interna e quella esterna. –

2

Questo funzionerà correttamente se è all'interno della tua @implementation. Ti consiglierei di renderlo un metodo normale, ma funziona.

Se si esclude dall'implementazione, si ottiene questo avviso: Avviso: la variabile di istanza '' è @protected; questo sarà un duro errore in futuro. È possibile evitare questo errore mettendo un @public prima iVar nell'intestazione ... in questo modo:

@public 
int myInt; 

che consente di accedere alle variabili come una C (puntatore) Struct laddove l'oggetto appare senza preavviso.

Quindi è fattibile, non consigliato però !!!

+0

penso che possa essere una cattiva pratica, ma non voglio esporre l'ivar come pubblico solo a favore dell'incapsulamento, ma le mie funzioni di callback C devono essere in grado di vedere l'istanza di ivars. – jlpiedrahita

+0

Allora dovresti fare quello che devi fare ... non devi dichiarare tutti i tuoi iVars come pubblici, puoi mescolare e abbinare. – micmoo

Problemi correlati