2010-01-04 21 views
12

Utilizzo Objective-C da un po 'di tempo ma essendo da uno sfondo di tipo statico (C#) penso di usarlo in modo molto statico. Dichiarare oggetti come id mi sembra estraneo a me e non riesco a vedere quali sono i benefici. Qualcuno può illuminare una luce per farmi capire meglio questo?Utilizzo ottimale delle funzioni dinamiche Objective-C

risposta

13

Objective-C è una specie di linguaggio ibrido, in cui puoi essere dinamico e statico quanto vuoi. Puoi dichiarare tutti i tipi di tutte le variabili se lo desideri, puoi anche dichiarare le variabili delegate come NSObject <Protocollo> * se lo desideri. Il tipo id funziona meno come un tipo reale e più come un suggerimento per il compilatore dicendogli "hey, so cosa sto facendo, fidati di me su questo", facendo in modo che il compilatore eviti qualsiasi tipo di controllo su quella particolare variabile .

Il primo evidente vantaggio del sistema di tipo Objective-C è che i tipi di container (NSArray, NSDictionary, NSSet) accettano e restituiscono tipi di ID. Ciò elimina completamente la necessità di template e generici (come in C++, Java e C#).

Ancora meglio, si possono effettivamente avere contenitori con elementi di qualsiasi tipo all'interno. Finché sai cosa succede, nessuno si lamenterà se aggiungi due NSStrings, un NSNumber e uno NSValue all'interno dello stesso NSArray. Puoi farlo in altre lingue, ma devi usare la classe base "Object", o il tipo void *, e quindi devi inserire le variabili box e unbox (o cast su e giù) per ottenere lo stesso comportamento. In Objective-C basta assegnare, il che rimuove il rumore generato dagli operatori di casting e dalle operazioni di boxe. Quindi puoi chiedere "respondsToSelector:" o "class" a ciascun oggetto, in modo da conoscere l'identità e le operazioni che puoi eseguire con essi, in fase di runtime. In Objective-C, la riflessione è un cittadino di prima classe.

Un altro vantaggio è la riduzione dei tempi di compilazione; la compilazione di un programma Objective-C è in generale molto più veloce del suo equivalente in C++, dato che non ci sono molti controlli di tipo eseguiti, e molti collegamenti sono fatti in runtime. Il compilatore si fida di più del programmatore.

Infine, il sistema di tipo dinamico di Objective-C rende possibile avere uno strumento come Interface Builder. Questo è il motivo principale per cui Cocoa e Cocoa Touch hanno tempi di sviluppo più rapidi; la GUI può generare codice con tipi "id" dappertutto, e questo viene deserializzato ogni volta che il NIB viene caricato in memoria. L'unico linguaggio che si avvicina a Objective-C in termini di esperienza nella progettazione dell'interfaccia utente è C# (e VB.NET, ovviamente) ma al prezzo di un'applicazione molto più pesante.

Personalmente preferisco lavorare con un controllo di tipo più statico, e accendo persino l'impostazione "Tratta avvertimenti come errori" nel compilatore Objective-C; Ho scritto un post su di esso:

http://akosma.com/2009/07/16/objective-c-compiler-warnings/

Ciò è particolarmente utile quando si lavora con gli sviluppatori che sono nuovi per la lingua. Fa in modo che il compilatore si lamenti più spesso del solito :)

Gli esperti del sistema di tipo statico potrebbero non essere d'accordo con tutti questi punti, sostenendo che il controllo statico dei tipi consente di avere IDE "intellisense" e una manutenzione migliore in generale. Ho lavorato con .NET per anni (2001 - 2006) e devo dire che i linguaggi dinamici tendono a produrre meno codice, sono più facili da leggere e, in generale, danno più libertà di lavoro. Il compromesso (c'è sempre un compromesso) è che ci sono meno informazioni al momento della compilazione. Ma come tendo a dire, i compilatori sono una serie di test di un uomo povero. La cosa migliore IMHO è avere una buona serie di test, e un buon gruppo di tester umani che torturano il tuo codice per trovare bug, indipendentemente dalla lingua che scegli.

+1

Grazie a @akosma per il tempo dedicato a scrivere questa risposta eccellente. : D –

3

In realtà è piuttosto raro che sia necessario dichiarare un oggetto come tipo id, in genere si dovrebbe sapere quale tipo si prevede. A volte è possibile utilizzare un tipo id<Protocol>, se non si conosce il tipo effettivo di un oggetto ma si sa che deve essere conforme a un protocollo specifico.

C'è uno scenario particolare a cui stai pensando?

+0

Sto usando l'id ma mi sembra fortemente digitato ed è analogo all'utilizzo di interfacce in C#. Ho visto persone dire che alcuni compiti diventano banali in linguaggi dinamici ma non hanno mai dato alcun esempio. Immagino che voglio solo assicurarmi di ottenere il massimo beneficio dal linguaggio e di non rendere le cose più difficili per me stesso pensando fortemente digitato. – Ian1971

2

L'istanza di passaggio come id è comune quando si progetta il metodo dell'azione; collegando un pulsante a un metodo, il target appare come doSomething:(id) sender;.

In questo caso, consente a diversi tipi di controlli di utilizzare il metodo della stessa azione, senza una conoscenza preliminare di ciò che questi controlli saranno. Nel codice del metodo dell'azione, puoi testare la classe del mittente o semplicemente usare la sua proprietà tag, per decidere cosa fare.

5

La dinamicità di Objective-C risplende non solo nel fatto che ogni oggetto è un id. Piuttosto, risplende nella potenza del runtime Objective-C e nella facilità di usarlo. Alcuni esempi di usi intelligenti del runtime da parte della stessa Apple:

DO consente di impostare un oggetto proxy per un oggetto Obj-C in un'app separata/macchina separata. Questo viene fatto intercettando tutto il messaggio inviato all'oggetto proxy, comprimendolo, inviandolo all'altra app e invocandolo lì.

KVO viene implementato sostituendo dinamicamente il metodo di setter in modo che esso avvisi automaticamente gli osservatori. (Beh, è ​​in realtà più sottile di quello ...)

CoreData accessors sono generati in fase di esecuzione per ogni sottoclasse di NSManagedObject, ecc

E, è possibile utilizzare il runtime dal codice, anche. Una volta l'ho usato per un buon effetto, imitando CoreData e generando accessor in fase di esecuzione e avendo solo la loro dichiarazione nel file di intestazione. In questo modo è possibile ottenere il merito sia della tipizzazione statica (errore del tempo di compilazione dalla dichiarazione nell'intestazione) che del dinamismo (generazione di metodi di runtime).

Mike Ash ha scritto un'eccellente serie di post sul blog su come funziona il runtime e su come utilizzarlo in modo efficace. Devi solo leggerlo! DO, KVO, message forwarding e altro ancora. Ci sono anche molti altri post interessanti sulla rete, come fun with kvc e la messaggistica di ordine superiore 1, 2.

+0

+1 Questa è una grande raccolta di link - grazie! –

Problemi correlati