¿Hay colecciones fuertemente mecanografiadas en Objective-C?


Soy nuevo en programación 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#

Dictionary<int, MyCustomObject>

Solo puede contener claves que sean enteros y valores que sean de tipo MyCustomObject. ¿Existe un mecanismo similar en Objective-C?

Author: Quinn Taylor, 2009-05-11

11 answers

En Xcode 7, Apple ha introducido 'Genéricos ligeros' a Objective-C. En Objective-C, generarán advertencias del compilador si hay un desajuste 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'

Los genéricos ligeros están diseñados para usarse con NSArray, NSDictionary y NSSet, pero también puede agregarlos 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 hizo 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 Rápido ignorará la información Genérica por completo. (Ya no es cierto en Swift 3+.)

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

Aparte de estas clases de colección Foundation, Swift ignora los genéricos ligeros de Objective-C. Cualquier otro tipo que use genéricos ligeros se importa a Swift como si no estuvieran comparados.

Interactuar con las API de Objective-C

 206
Author: Connor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-01 16:52:30

Esta respuesta es anticuada pero permanece por valor histórico. A partir de Xcode 7, la respuesta de Connor del 8 de junio del 15 es más precisa.


No, no hay genéricos en Objective-C a menos que desee usar plantillas de C++ en sus propias clases de colecciones personalizadas (lo cual desaconsejo encarecidamente).

Objective-C tiene la tipificación dinámica como una característica, lo que significa que el tiempo de ejecución no se preocupa por el tipo de un objeto ya que todos los objetos pueden recibir mensajes. Cuando se agrega un objeto para una colección incorporada, solo se tratan como si fueran de tipo id. Pero no se preocupe, simplemente envíe mensajes a esos objetos como de costumbre; funcionará bien (a menos que, por supuesto, 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 fuertes y estáticamente tipeados. Juego de pelota totalmente diferente a la función de escritura dinámica de Objective-C.

 91
Author: Marc W,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-08 04:09:35

No, pero para hacerlo más claro puedes comentarlo con el tipo de objeto que deseas almacenar, he visto esto varias veces cuando necesitas escribir algo en Java 1.4 hoy en día) por ejemplo:

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

O

NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
 11
Author: Mark Rhodes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-19 23:31:45

No hay genéricos en Objective-C.

De los documentos

Los arrays son colecciones ordenadas de objetos. Cocoa proporciona varias clases de array, NSArray, NSMutableArray (una subclase de NSArray), y NSPointerArray.

 6
Author: Matthew Vines,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-11 15:34:43

Apple ha añadido genéricos a ObjC en XCode 7:

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

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

 6
Author: user1259710,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-08 22:13:25

Esto fue lanzado en Xcode 7 (finalmente!)

Tenga en cuenta que en el código de Objective C, es solo una comprobación en tiempo de compilación; no habrá ningún error en tiempo de ejecución solo por poner el tipo incorrecto en una colección o asignar a una propiedad de tipo.

Declarar:

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

Uso:

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

Tenga cuidado con esos *s.

 5
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-09 16:38:35

Los NSArrays genéricos se pueden realizar subclasificando NSArray, y redefiniendo todos los métodos proporcionados con otros más restrictivos. Por ejemplo,

- (id)objectAtIndex:(NSUInteger)index

Tendría que ser redefinido en

@interface NSStringArray : NSArray

Como

- (NSString *)objectAtIndex:(NSUInteger)index

Para que un NSArray contenga solo NSStrings.

La subclase creada se puede usar como un reemplazo desplegable y trae muchas características útiles: advertencias del compilador, acceso a propiedades, mejor creación y finalización de código en Xcode. Todos estos son en tiempo de compilación características, no hay necesidad de redefinir la implementación real-los métodos de NSArray todavía se pueden utilizar.

Es posible automatizar esto y reducirlo a solo dos sentencias, lo que lo acerca a los lenguajes que admiten genéricos. He creado 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 una para la implementación. Solo necesita proporcionar el tipo de datos que desea almacenar y los nombres para sus subclases. WMGenericCollection proporciona tales plantillas para NSArray, NSDictionary y NSSet, así como sus contrapartes mutables.

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

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

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

 4
Author: w-m,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-04 22:13:40

Echa un vistazo a:

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

Parece ser una especie de genéricos de los pobres, al reutilizar el mecanismo de verificación del protocolo.

 2
Author: David Jeske,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-01 16:47:21

Ahora los sueños se hacen realidad - hay genéricos en Objective-C desde hoy (gracias, WWDC). No es una broma - en página oficial de Swift:

Las nuevas características de sintaxis le permiten escribir código más expresivo al tiempo que mejora la consistencia en todo el lenguaje. Los SDK han empleado nuevas características de Objective-C como los genéricos y la anotación de nullability para hacer que el código Swift sea aún más limpio y seguro. Aquí hay solo una muestra de las mejoras de Swift 2.0.

E imagen que prueba esto: Objective-C genéricos

 2
Author: htzfun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-09 14:54:23

Sólo quiero saltar aquí. He escrito una entrada de blog aquí sobre genéricos.

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

He agregado con éxito una variedad de clases, ya que funcionan exactamente igual que las colecciones de Apple. IE. comprobación del tiempo de compilación, finalización de código, habilitación de la eliminación de casts, etc.

Disfruta.

 2
Author: drekka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-16 12:07:32

Las clases Collections proporcionadas por Apple y GNUstep frameworks son semi-genéricas en el sentido de que asumen que se les dan objetos, algunos que son clasificables y otros que responden a ciertos mensajes. Para primitivas como floats, ints, etc, toda la estructura de arrays C está intacta y se puede usar, y hay objetos especiales de envoltura para usarlos en las clases de colección general (por ejemplo, NSNumber). Además, una clase de colección puede ser subclasificada (o modificada específicamente a través de categorías) para acepta objetos de cualquier tipo, pero tienes que escribir todo el código de manejo de tipos tú mismo. Los mensajes pueden ser enviados a cualquier objeto, pero deben devolver null si no es apropiado para el objeto, o el mensaje debe ser reenviado a un objeto apropiado. Los errores de tipo verdadero deben detectarse en tiempo de compilación, no en tiempo de ejecución. En tiempo de ejecución deben ser manejados o ignorados. Por último, Objc proporciona instalaciones de reflexión en tiempo de ejecución para manejar casos difíciles y la respuesta de mensajes, el tipo específico y los servicios pueden ser se comprueba en un objeto antes de que sea enviado un mensaje o puesto en una colección inapropiada. Tenga en cuenta que las bibliotecas y frameworks dispares adoptan diferentes convenciones en cuanto a cómo se comportan sus objetos cuando se 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 tener que bloquearse a menos que realmente lo arruinen e intenten escribir datos incorrectos en la memoria o el disco, realicen operaciones ilegales (por ejemplo, dividir por cero, pero también puede atraparlo), o acceso a 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 estar integradas en su código. (PISTA) si usted está teniendo problemas con la genericidad en sus funciones, intente un poco de 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 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];
 -2
Author: Chris Reid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-10 23:41:39