137

Soy nuevo en la programación de Mac/iPhone y Objective-C. En C# y Java tenemos "genéricos", clases de colección cuyos miembros solo pueden ser del tipo declarado. Por ejemplo, en C#¿Hay colecciones fuertemente tipadas en Objective-C?

Dictionary<int, MyCustomObject>

sólo puede contener las claves que son números enteros y valores que son de tipo MyCustomObject. ¿Existe un mecanismo similar en Objective-C?

+0

Estoy empezando a aprender acerca de ObjC. ¿Quizás pueda usar ObjC++ para hacer el trabajo pesado? – Toybuilder

+2

ObjC++ no es realmente un lenguaje ... simplemente una manera más de referenciar la capacidad de ObjC para manejar C++ en línea de la misma manera que manejaría C.Sin embargo, no debes hacer esto a menos que tengas que hacerlo (por ejemplo, si necesitas usar una biblioteca de terceros escrita en C++). –

+0

Más o menos un duplicado exacto de http://stackoverflow.com/questions/649483/is-there-any-way-to-enforce-typing-on-nsarray-nsmutablearray-etc –

Respuesta

205

En Xcode 7, Apple ha presentado 'Lightweight Generics' para Objective-C. En Objective-C, generarán advertencias de compilador si hay una discrepancia de tipo.

NSArray<NSString*>* arr = @[@"str"]; 

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

y en el código Swift, producirán un error del compilador:

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

Genéricos ligeros están destinados a ser utilizados con NSArray, NSDictionary y NSSet, pero también se puede añadir a sus propias clases :

@interface GenericsTest<__covariant T> : NSObject 

-(void)genericMethod:(T)object; 

@end 

@implementation GenericsTest 

-(void)genericMethod:(id)object {} 

@end 

Objective-C se comportará como lo hacía antes con las advertencias del compilador.

GenericsTest<NSString*>* test = [GenericsTest new]; 

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

pero Swift ignorará por completo la información genérica. (Ya no cierto en Swift 3+.)

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

Aside from than these Foundation collection classes, Objective-C lightweight generics are ignored by Swift. Any other types using lightweight generics are imported into Swift as if they were unparameterized.

Interacting with Objective-C APIs

+0

Como tengo dudas sobre los genéricos y los tipos devueltos en los métodos, hice mi pregunta en hilo diferente, para mantener todo claro: http://stackoverflow.com/questions/30828076/objective-c-generics-not-working-for-methods – lvp

+0

¿Puedes usar esto solo con Xcode 7? – rizzes

+2

@rizzes. Sí, fue presentado. – connor

6

No hay genéricos en Objective-C.

From the Docs

Arrays are ordered collections of objects. Cocoa provides several array classes, NSArray, NSMutableArray (a subclass of NSArray), and NSPointerArray.

91

This answer is outdated but remains for historical value. As of Xcode 7, Connor's answer from Jun 8 '15 is more accurate.


No, no hay genéricos en Objective-C, a menos que desee utilizar las plantillas de C++ en sus propias clases de colección personalizado (que fuerte desanimo).

Objective-C tiene una función de tipado dinámico, lo que significa que al motor de ejecución no le importa el tipo de objeto, ya que todos los objetos pueden recibir mensajes. Cuando agrega un objeto a una colección integrada, simplemente se tratan como si fueran del tipo id. Pero no te preocupes, solo envía mensajes a esos objetos como lo normal; Funcionará bien (a menos que uno o más de los objetos de la colección no respondan al mensaje que está enviando).

Los genéricos son necesarios en lenguajes como Java y C# porque son lenguajes sólidos y estáticos. Juego de pelota totalmente diferente a la función de tipado dinámico de Objective-C.

+87

No estoy de acuerdo con "no se preocupe, solo envíe mensajes a esos objetos". Si coloca el tipo incorrecto de objetos en la colección, que no responden a estos mensajes, esto generará errores de tiempo de ejecución. El uso de genéricos en otros idiomas evita este problema con las comprobaciones del tiempo de compilación. – henning77

+8

@ henning77 Sí, pero Objective-C es un lenguaje más dinámico que estos idiomas. Si desea una seguridad de tipo fuerte, use esos idiomas. –

+36

También estoy en desacuerdo con la filosofía de no preocuparse: por ejemplo, si extrae el primer elemento de un NSArray y lo lanza a un NSNumber, pero ese elemento era realmente un NSSumber, está jodido ... – jjxtra

11

No, pero para hacerlo más claro se puede comentar con el tipo de objeto que desea almacenar, he visto este hecho un par de veces cuando se necesita para escribir algo en Java 1.4 hoy en día) por ejemplo:

NSMutableArray* /*<TypeA>*/ arrayName = .... 

o

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ... 
+0

Supongo que esta es una buena manera de documentarlo, en caso de que alguien más lea tu código. De todos modos, el nombre de la variable debe ser lo más claro posible para saber qué objetos contiene. – htafoya

-2

Las clases Colecciones marcos proporcionados por Apple y gnustep son semi-genérica en que se suponen que son objetos dados, algunos que se pueden ordenar y algunos que responden a ciertos mensajes. Para primitivas como flotadores, ints, etc., toda la estructura de las matrices C está intacta y puede utilizarse, y hay objetos especiales para ellas para su uso en las clases de recopilación generales (por ejemplo, NSNumber). Además, una clase Collection puede ser subclasificada (o modificada específicamente por categorías) para aceptar objetos de cualquier tipo, pero usted debe escribir todo el código de manejo de tipos usted mismo. Los mensajes pueden enviarse a cualquier objeto pero deben devolver nulo si no es apropiado para el objeto, o el mensaje debe enviarse a un objeto apropiado. Los errores de tipo verdadero deben capturarse en tiempo de compilación, no en tiempo de ejecución. En tiempo de ejecución deben ser manejados o ignorados. Finalmente, Objc proporciona recursos de reflexión en tiempo de ejecución para manejar casos complicados y se puede verificar la respuesta del mensaje, tipo específico y servicios en un objeto antes de enviar un mensaje o ponerlo en una colección inapropiada. Tenga en cuenta que las bibliotecas y marcos dispares adoptan diferentes convenciones sobre cómo se comportan sus objetos cuando envían mensajes para los que no tienen respuestas de código, por lo que RTFM. Aparte de los programas de juguete y las compilaciones de depuración, la mayoría de los programas no deberían fallar a menos que realmente se arruinen y traten de escribir datos incorrectos en la memoria o el disco, realizar operaciones ilegales (por ejemplo, dividir por cero, pero también puedes ver eso) o acceder recursos del sistema fuera de los límites El dinamismo y el tiempo de ejecución de Objective-C permiten que las cosas fallen correctamente y deben incorporarse a su código. (SUGERENCIA) Si tiene problemas con la genérica en sus funciones, pruebe alguna especificidad. Escriba las funciones con tipos específicos y deje que el tiempo de ejecución seleccione (¡por eso se llaman selectores!) La función de miembro apropiada en tiempo de ejecución.

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

NSArrays genéricos se pueden realizar por subclases NSArray, y la redefinición de todos los métodos proporcionados por otros más restrictivas. Por ejemplo,

- (id)objectAtIndex:(NSUInteger)index 

tendrían que ser redefinido en

@interface NSStringArray : NSArray 

como

- (NSString *)objectAtIndex:(NSUInteger)index 

para una NSArray a contener sólo NSStrings.

La subclase creada se puede utilizar como un reemplazo directo y ofrece muchas funciones útiles: advertencias de compilación, acceso a la propiedad, mejor creación de código y -completado en Xcode. Todas estas son características de tiempo de compilación, no hay necesidad de redefinir la implementación real. Los métodos de NSArray aún se pueden usar.

Es posible automatizar esto y reducirlo a solo dos declaraciones, lo que lo acerca a los lenguajes que admiten genéricos. Creé una automatización con WMGenericCollection, donde las plantillas se proporcionan como Macros de preprocesador C.

Después de importar el archivo de encabezado que contiene la macro, puede crear un NSArray genérico con dos instrucciones: una para la interfaz y otra para la implementación. Solo necesita proporcionar el tipo de datos que desea almacenar y los nombres de sus subclases. WMGenericCollection proporciona tales plantillas para NSArray, NSDictionary y NSSet, así como sus contrapartes mutables.

Un ejemplo: List<int> podría realizarse por una clase personalizada llamada NumberArray, que se crea con la siguiente afirmación:

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

vez que haya creado NumberArray, puede usarlo en todas partes en su proyecto. Carece de la sintaxis de <int>, pero puede elegir su propio esquema de nombres para etiquetarlos como clases como plantillas.

+0

tenga en cuenta que lo mismo existe en CoreLib: https://github.com/core-code/CoreLib/blob/master/CoreLib/CoreLib.h#L105 – user1259710

2

Ahora los sueños se hacen realidad - hay genéricos en el objetivo- C desde hoy (gracias, WWDC). No es una broma - en official page de Swift:

New syntax features let you write more expressive code while improving consistency across the language. The SDKs have employed new Objective-C features such as generics and nullability annotation to make Swift code even cleaner and safer. Here is just a sampling of Swift 2.0 enhancements.

y la imagen que las pruebas esto: Objective-C generics

5

This was released in Xcode 7

Tenga en cuenta que en el código de Objective C, que es sólo una de compilación (por fin!) chequeo de tiempo; no habrá error en tiempo de ejecución solo por poner el tipo incorrecto en una colección o asignarlo a una propiedad mecanografiada.

declaran:

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

Uso:

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

tener cuidado con los * s.

+0

Hermoso. :) Gracias por la actualización. – Qix

2

Solo quiero entrar aquí. He escrito una publicación de blog over here sobre Generics.

Lo que quiero contribuir es que genéricos se pueden agregar a cualquier clase, no solo a las clases de colección como indica Apple.

He agregado con éxito luego a una variedad de clases, ya que funcionan exactamente igual que las colecciones de Apple. es decir. tiempo de compilación, código de finalización, que permite la eliminación de moldes, etc.

Disfrútalo.

Cuestiones relacionadas