Ci sono collezioni fortemente tipizzate in Objective-C?

Sono nuovo di programmazione per Mac / iPhone e Objective-C. In C # e Java abbiamo “generici”, classi di raccolta i cui membri possono essere solo del tipo dichiarato. Ad esempio, in C #

Dictionary

può contenere solo chiavi che sono numeri interi e valori che sono di tipo MyCustomObject. Esiste un meccanismo simile in Objective-C?

In Xcode 7, Apple ha introdotto “Lightweight Generics” su Objective-C. In Objective-C, genereranno avvisi del compilatore in caso di mancata corrispondenza del tipo.

 NSArray* arr = @[@"str"]; NSString* string = [arr objectAtIndex:0]; NSNumber* number = [arr objectAtIndex:0]; // Warning: Incompatible pointer types initializing 'NSNumber *' with an expression of type 'NSString *' 

E nel codice Swift, produrranno un errore del compilatore:

 var str: String = arr[0] var num: Int = arr[0] //Error 'String' is not convertible to 'Int' 

I generici leggeri sono destinati all’uso con NSArray, NSDictionary e NSSet, ma è ansible aggiungerli anche alle proprie classi:

 @interface GenericsTest<__covariant T> : NSObject -(void)genericMethod:(T)object; @end @implementation GenericsTest -(void)genericMethod:(id)object {} @end 

Objective-C si comporterà come prima con gli avvertimenti del compilatore.

 GenericsTest* test = [GenericsTest new]; [test genericMethod:@"string"]; [test genericMethod:@1]; // Warning: Incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *' 

ma Swift ignorerà completamente le informazioni generiche. (Non è più vero in Swift 3+.)

 var test = GenericsTest() //Error: Cannot specialize non-generic type 'GenericsTest' 

Oltre a queste classi di raccolta della Fondazione, i generici leggeri Objective-C vengono ignorati da Swift. Tutti gli altri tipi che utilizzano generici leggeri vengono importati in Swift come se fossero non parametrizzati.

Interagire con le API Objective-C

Questa risposta è obsoleta ma rimane per valore storico. A partire da Xcode 7, la risposta di Connor dell’8 giugno ’15 è più accurata.


No, non ci sono generici in Objective-C a meno che non si vogliano usare i template C ++ nelle proprie classi di raccolta personalizzate (che sconsiglio vivamente).

Objective-C ha una digitazione dynamic come funzione, il che significa che al runtime non interessa il tipo di un object poiché tutti gli oggetti possono ricevere messaggi. Quando aggiungi un object a una raccolta predefinita, vengono trattati come se fossero id tipo. Ma non preoccuparti, basta inviare messaggi a quegli oggetti come normali; funzionerà correttamente (a meno che uno o più degli oggetti nella raccolta non rispondano al messaggio che stai inviando) .

I generici sono necessari in linguaggi come Java e C # perché sono lingue forti, tipizzate staticamente. Gioco di palla completamente diverso dalla funzione di digitazione dynamic di Objective-C.

No, ma per renderlo più chiaro puoi commentare con il tipo di object che vuoi memorizzare, l’ho visto fare alcune volte quando devi scrivere qualcosa in Java 1.4 al giorno d’oggi) ad esempio:

 NSMutableArray* /**/ arrayName = .... 

o

 NSDictionary* /**/ dictionaryName = ... 

Non ci sono generici in Objective-C.

Dai documenti

Le matrici sono raccolte ordinate di oggetti. Cocoa fornisce diverse classi di array, NSArray, NSMutableArray (una sottoclass di NSArray) e NSPointerArray.

Apple ha aggiunto farmaci generici a ObjC in XCode 7:

 @property NSArray* dates; - (NSArray *)datesBeforeDate:(NSDate *)date; - (void)addDatesParsedFromTimestamps:(NSArray *)timestamps; 

vedere qui: https://developer.apple.com/library/prerelease/mac/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html#//apple_ref/doc/uid/TP40014216-CH6-ID61

Questo è stato rilasciato in Xcode 7 (finalmente!)

Si noti che nel codice Objective C, è solo un controllo in fase di compilazione; non ci sarà nessun errore di run-time solo per inserire il tipo sbagliato in una collezione o assegnarlo a una proprietà tipizzata.

Dichiarare:

 @interface FooClass  : NSObject @property (nonatomic) T prop; @end 

Uso:

 FooClass *foo = [[FooClass alloc] init]; NSArray *> *fooAry = [NSArray array]; 

Stai attento a quelli * s.

Gli NSArrays generici possono essere realizzati sottoclassando NSArray e ridefinendo tutti i metodi forniti con quelli più restrittivi. Per esempio,

 - (id)objectAtIndex:(NSUInteger)index 

dovrebbe essere ridefinito in

 @interface NSStringArray : NSArray 

come

 - (NSString *)objectAtIndex:(NSUInteger)index 

per un NSArray per contenere solo NSStrings.

La sottoclass creata può essere utilizzata come una sostituzione drop-in e offre molte utili funzionalità: avvisi del compilatore, accesso alle proprietà, migliore creazione del codice e completamento in Xcode. Tutte queste funzionalità sono in fase di compilazione, non è necessario ridefinire l’effettiva implementazione: i metodi di NSArray possono ancora essere utilizzati.

È ansible automatizzarlo e ridurlo a due sole affermazioni, il che lo avvicina alle lingue che supportano i generici. Ho creato un’automazione con WMGenericCollection , dove i modelli sono forniti come macro preprocessore C.

Dopo aver importato il file di intestazione contenente la macro, è ansible creare un NSArray generico con due istruzioni: una per l’interfaccia e una per l’implementazione. Devi solo fornire il tipo di dati che desideri archiviare e i nomi delle sottoclassi. WMGenericCollection fornisce tali modelli per NSArray , NSDictionary e NSSet , nonché per le loro controparti mutabili.

Un esempio: List potrebbe essere realizzato da una class personalizzata chiamata NumberArray , che viene creata con la seguente dichiarazione:

 WMGENERICARRAY_INTERFACE(NSNumber *, // type of the value class // generated class names NumberArray, MutableNumberArray) 

Dopo aver creato NumberArray , puoi utilizzarlo ovunque nel tuo progetto. Manca la syntax di , ma puoi scegliere il tuo schema di denominazione per etichettarli come classi come modelli.

Dare un’occhiata a:

https://github.com/tomersh/Objective-C-Generics

Sembra essere una specie di generici dei poveri, riutilizzando il meccanismo di controllo del protocollo.

Ora i sogni diventano realtà – ci sono Generics in Objective-C da oggi (grazie, WWDC). Non è uno scherzo – nella pagina ufficiale di Swift:

Le nuove funzionalità di syntax ti consentono di scrivere più codice espressivo migliorando al tempo stesso la coerenza in tutto il linguaggio. Gli SDK hanno utilizzato nuove funzioni Objective-C come l’annotazione generica e nullability per rendere il codice Swift ancora più pulito e sicuro. Ecco solo alcuni esempi di miglioramenti di Swift 2.0.

E l’immagine che prova questo: Generici oggettivi-C

Voglio solo saltare qui. Ho scritto un post sul blog qui su Generics.

La cosa che voglio dare è che Generics può essere aggiunto a qualsiasi class , non solo alle classi di raccolta come indica Apple.

Ho aggiunto con successo a una varietà di classi perché funzionano esattamente come fanno le raccolte di Apple. vale a dire. compilare il controllo del tempo, completare il codice, abilitare la rimozione dei cast, ecc.

Godere.

Le classi Collections fornite dai framework Apple e GNUStep sono semi-generiche in quanto presuppongono che gli vengano assegnati oggetti, alcuni che sono ordinabili e altri che rispondono a determinati messaggi. Per le primitive come float, int, ecc, tutta la struttura dei C array è intatta e può essere utilizzata, e per essi sono disponibili speciali oggetti wrapper da utilizzare nelle classi di raccolta generali (ad es. NSNumber). Inoltre, una class Collection può essere sottoclassata (o modificata in modo specifico tramite categorie) per accettare oggetti di qualsiasi tipo, ma è necessario scrivere da soli tutti i codici di gestione dei tipi. I messaggi possono essere inviati a qualsiasi object, ma devono restituire null se è inappropriato per l’object o il messaggio deve essere inoltrato a un object appropriato. I veri errori di tipo dovrebbero essere rilevati in fase di compilazione, non in fase di esecuzione. In fase di esecuzione dovrebbero essere gestiti o ignorati. Infine, Objc fornisce funzionalità di riflessione in fase di esecuzione per gestire casi complicati e la risposta dei messaggi, il tipo specifico ei servizi possono essere controllati su un object prima che venga inviato un messaggio o inserito in una raccolta inappropriata. Fai attenzione che librerie e framework disparati adottano convenzioni diverse su come si comportano gli oggetti quando i messaggi inviati non hanno risposte di codice, quindi RTFM. A parte i programmi giocattolo e le build di debug, la maggior parte dei programmi non dovrebbe andare in crash a meno che non rovini davvero e provi a scrivere dati cattivi su memoria o disco, esegua operazioni illegali (es. Dividi per zero, ma puoi catturare anche questo) o accedi risorse di sistema off-limits. Il dinamismo e il tempo di esecuzione di Objective-C consente alle cose di fallire con garbo e dovrebbero essere integrate nel codice. (SUGGERIMENTO) se hai problemi con la genericità delle tue funzioni, prova qualche specificità. Scrivi le funzioni con tipi specifici e lascia che il runtime selezioni (questo è il motivo per cui sono chiamati selettori!) La funzione membro appropriata in fase di esecuzione.

 Example: -(id) sort (id) obj; // too generic. catches all. // better -(id) sort: (EasilySortableCollection*) esc; -(id) sort: (HardToSortCollection*) hsc; ... [Sorter sort: MyEasyColl]; [Sorter sort: MyHardColl];