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
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.
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?
Sto usando l'id
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.
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.
+1 Questa è una grande raccolta di link - grazie! –
- 1. Python definire le funzioni dinamiche
- 2. Javascript: nomi di funzioni dinamiche
- 3. Nomi di funzioni dinamiche Python
- 4. Funzioni dinamiche C++ e FULLY
- 5. Utilizzo delle funzioni freccia con d3
- 6. Utilizzo delle funzioni di applicazione in SparkR
- 7. Utilizzo delle funzioni sys/socket.h su windows
- 8. Uso delle funzioni lambda C++ 11 in ARC ObjectiveC++ - come farlo correttamente?
- 9. ObjectiveC blocca l'equivalente Java
- 10. Utilizzo delle funzioni min e max in C++
- 11. Utilizzo della distanza Bhattacharyya per la selezione delle funzioni
- 12. Utilizzo delle funzioni HMAC e EVP in OpenSSL
- 13. Utilizzo delle funzioni di valutazione lazy in varargs
- 14. Schema per il supporto delle proprietà dinamiche
- 15. Partizionamento delle tabelle dinamiche in postgres
- 16. Implementare protocollo ObjectiveC in rapida
- 17. Dipendenze delle funzioni nell'albero di selezione delle funzioni in Wix
- 18. un elenco di funzioni dinamiche e chiamarle dinamicamente
- 19. Scala - Creazione di un parser di funzioni dinamiche di base
- 20. Ottimale fattore di lavoro bcrypt
- 21. Comportamento incoerente delle funzioni
- 22. Parallelo * all'interno delle funzioni
- 23. Elenco delle funzioni OpenCV
- 24. Ereditarietà delle funzioni virtuali
- 25. Utilizzo di funzioni anonime autoinvitrici
- 26. Prestazioni delle funzioni MySql Xml?
- 27. Comprensione delle liste negli argomenti delle funzioni
- 28. Conseguenza delle prestazioni delle funzioni membro volatile
- 29. Configurazione ottimale delle tabelle temporanee MySQL (tabelle di memoria)?
- 30. Differenza tra NSLog e printf per ObjectiveC
Grazie a @akosma per il tempo dedicato a scrivere questa risposta eccellente. : D –