2009-07-30 11 views
7

Ho una funzione che desidero utilizzare su due diversi oggetti personalizzati. Il mio primo pensiero è stato accettare l'argomento come (id) e operare sull'oggetto id. Tuttavia, non riesco a capire come farlo.Utilizzo di (id) in Objective-C

Entrambe le classi (dire mele e arance) hanno variabili dell'interfaccia:

NSDecimalNumber *count; 

voglio fare qualcosa di simile a questo:

-(NSDecimalNumber*)addCount:(id)addObject{ 

    return [count decimalNumberByAdding:addObject.count]; 
} 

io non riesco a capire la sintassi per fallo accadere. È questo l'approccio corretto, o sarebbe meglio sottoclasse (da parte di una classe di frutta) e operare sulla classe genitore?

-(NSDecimalNumber*)addCount:(Fruit*)addFruit{ 

    return [count decimalNumberByAdding:addFruit.count]; 
} 

risposta

12

Mentre è possibile inviare un messaggio a qualsiasi oggetto (id) - gli accessor di proprietà richiedono che il compilatore sia consapevole del tipo con cui si ha a che fare - questo perché gli accessor di proprietà sono zucchero sintattico attorno alla chiamata di metodi getter e setter specifici.

avete un paio di modi di lavorare attorno a questo:

  1. Invece di accedere alla proprietà conteggio, chiamare i metodi corrispondenti [getCount].

  2. Se le diverse classi hanno differenti versioni di questo metodo, è possibile utilizzare un controllo di tipo runtime:

  3. Fornire una classe di base per entrambi i tipi in modo che è possibile passare a qualcosa di più specifico rispetto (id).

  4. Definire e implementare un protocollo che entrambi gli oggetti implementano che definisce una proprietà (o metodo) di conteggio.

Esempio di un controllo di tipo dinamico:

if([object isKindOfClass:[Apple Class]) 
    // call one overload of getCount 
else if([object isKindOfClass:[Orange Class]) 
    // call another overload of getCount 

Personalmente, prediligo la tipizzazione forte nel mio codice perché rende più facile capire l'intento. Consente inoltre all'IDE di supportare lo sforzo di codifica con intellisense, analisi statiche e funzionalità di refactoring. Quindi, nel tuo caso, utilizzerei il n. 3 o il n. 4 come approccio, a seconda che l'ereditarietà sia davvero appropriata per il problema.

+1

Sono un fan di battere forte me stesso (sono andato con # 4 FYI). Grazie mille per l'informazione; Questo e 'esattamente quello che stavo cercando! –

+0

Se hai davvero bisogno di una forte digitazione, potresti avere un tempo migliore con un linguaggio statico come C++. È un peccato che le proprietà si comportino in questo modo asimmetrico. Per lo meno dovrebbe esserci un flag di compilazione per consentire il comportamento di compilazione simmetrica tra la sintassi delle proprietà e la sintassi del metodo ricevitore. – ctpenrose

+0

@ctpenrose Obj-C può essere digitato staticamente come la lingua successiva se lo si desidera. – kubi

0

Stai inviando il messaggio per contare, che cosa conta? id è un puntatore a qualsiasi tipo di oggetto. Se si prevede che l'oggetto abbia una proprietà count, allora si dovrebbe essere in grado di passare solo una matrice (o qualche altra restrizione di tipo).

-(NSDecimalNumber*)addCount:(NSArray*) Object{ 

return [count decimalNumberByAdding: [Object count]]; 

} 
0

A quanto mi risulta, id non ha nessuna metodi o variabili associate con esso, perché si tratta di un puntatore generico che non si riferisce a una classe specifica. This page ha alcune buone informazioni sugli ID se scorri un po '.

anObject questo non avrà una variabile count, motivo per cui il primo tentativo non funzionerà. Creare una classe base e usarla come parametro per il metodo mi sembra l'idea migliore.

8

Si dovrebbe cercare di non accedere alle variabili di istanza da un'altra classe.

In Objective-C è sufficiente che i due oggetti rispondano allo stesso selettore (ad esempio count), tuttavia ciò fornirebbe un avviso del compilatore.

Esistono due modi per eliminare questo avviso: sottoclasse da una classe comune Fruit o facendo sì che le due classi siano conformi a un protocollo. Mi piacerebbe andare con il protocollo:

@protocol FruitProtocol 

- (NSDecimalNumber *)count; 

@end 

@interface Orange : NSObject<FruitProtocol> 
@end 

@interface Apple : NSObject<FruitProtocol> 
@end 

Poi il metodo può apparire come segue:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addFruit { 
    return [count decimalNumberByAdding:[addFruit count]]; 
} 

Qui si sta dicendo che il vostro addCount aspetta qualsiasi oggetto che è conforme al protocollo FruitProtocol, e quindi può rispondere al selettore count, quindi il compilatore lo accetterà.

+0

wrt/"Non è possibile accedere alle variabili di istanza da un'altra classe." Certamente puoi. Se si digita staticamente un oggetto, ad esempio "Oggetto MYObject", allora è possibile accedere alle sue variabili di istanza da qualsiasi classe con l'operatore '->'. Ad esempio, supponendo che 'MYObject' abbia avuto un' int' ivar chiamato 'count', è possibile utilizzare' int myCount = object-> count; 'per accedervi. Le protezioni fornite da '@ private', ecc. Sono solo cosmetiche, anche in ObjC2. – johne

+0

Questo è fantastico! Il tuo esempio di codice mi ha facilitato l'implementazione senza ulteriori scavi. Grazie mille! –

+0

Hai ragione johne, lo cambierò in "non dovresti". Grazie – pgb

1

Il fatto che si stia tentando di accedere a "addFruit.count" è il problema. La sintassi del punto è solo per le proprietà dichiarate con @property (o per le strutture). Se si cambia in

[addFruit count] 

e aggiungere

-(NSDecimalNumber*)count 
{ 
    return [[count retain] autorelease]; 
} 

a ciascuna classe, allora avrebbe funzionato. Tuttavia, noterai che riceverai un avviso che dice che l''id' potrebbe non rispondere al messaggio 'count' e, a meno che tu non possa essere assolutamente sicuro che gli articoli inviati a questo metodo implementino un metodo 'count', questo è un approccio problematico .

Sono d'accordo con l'approccio di pgb. È necessario definire un protocollo e dichiarare entrambe le classi per implementarlo. Questo elimina il problema di non sapere se l'oggetto risponderà al "conteggio" o meno, dato che ora hai un "contratto" di sorta.

Se si desidera mantenere la sintassi punto con una proprietà, è possibile dichiarare che nel protocollo:

@protocol FruitProtocol 

@property(readonly) NSDecimalNumber * count; 

- (NSDecimalNumber *)count 

@end 

e poi, la funzione potrebbe essere:

-(NSDecimalNumber*)addCount:(id<FruitProtocol>)addObject{ 

    return [count decimalNumberByAdding:addObject.count]; 

} 
+0

Ottimo anche! Non l'ho capito prima. Grazie per il consiglio! –

Problemi correlati