objective c - caracteristicas - ¿Hay colecciones fuertemente tipadas en Objective-C?
objective c vs swift (11)
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 #
Dictionary<int, MyCustomObject>
solo puede contener claves que son enteros y valores que son de tipo MyCustomObject. ¿Existe un mecanismo similar en Objective-C?
Esta respuesta está desactualizada pero sigue teniendo un valor histórico. A partir de Xcode 7, la respuesta de Connor del Jun 8 ''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 colección personalizadas (lo cual desaconsejo enfáticamente).
Objective-C tiene una función de tipado dinámico, lo que significa que al tiempo 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 id
tipo. Pero no te preocupes, solo envía mensajes a esos objetos como lo normal; funcionará bien (a menos, por supuesto, que uno o más de los objetos en 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.
Ahora los sueños se hacen realidad: hay genéricos en Objective-C desde hoy (gracias, WWDC). No es una broma, en la página oficial de Swift:
Las nuevas características de sintaxis le permiten escribir un código más expresivo mientras mejora la coherencia en todo el idioma. Los SDK han empleado nuevas características de Objective-C, como los genéricos y la anotación de anulabilidad, 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.
Y la imagen que prueba esto:
Apple ha agregado genéricos a ObjC en XCode 7:
@property NSArray<NSDate *>* dates;
- (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;
Echa un vistazo a:
https://github.com/tomersh/Objective-C-Generics
Parece ser una especie de genéricos de pobres, al reutilizar el mecanismo de verificación del protocolo.
En Xcode 7, Apple ha presentado ''Lightweight Generics'' a 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 de compilación:
var str: String = arr[0]
var num: Int = arr[0] //Error ''String'' is not convertible to ''Int''
Los genéricos ligeros están destinados a ser utilizados 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 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 es cierto en Swift 3+).
var test = GenericsTest<String>() //Error: Cannot specialize non-generic type ''GenericsTest''
Además de estas clases de colección de la Fundación, Swift ignora los genéricos ligeros Objective-C. Cualquier otro tipo que use genéricos ligeros se importa a Swift como si no estuviera parametrizado.
Las clases de Colecciones proporcionadas por Apple y los marcos de GNUStep son semigenéricas, ya que suponen que se les asignan objetos, algunos que son ordenables y otros 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 reenviarse 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];
Los NSArrays genéricos se pueden realizar mediante la subclasificación de NSArray
y la redefinición de todos los métodos proporcionados con los 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 utilizar como un reemplazo directo y trae muchas funciones útiles: advertencias del compilador, 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. WMGenericCollection una automatización con WMGenericCollection , donde las plantillas se proporcionan como Macros de preprocesador C.
Después de importar el archivo de cabecera 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 homólogos mutables.
Un ejemplo: List<int>
podría realizarse mediante 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 cualquier lugar de su proyecto. Carece de la sintaxis de <int>
, pero puede elegir su propio esquema de nombres para etiquetarlos como clases como plantillas.
No hay genéricos en Objective-C.
Las matrices son colecciones ordenadas de objetos. Cocoa proporciona varias clases de matriz, NSArray, NSMutableArray (una subclase de NSArray) y NSPointerArray.
No, pero para hacerlo más claro puedes comentarlo con el tipo de objeto que deseas almacenar, lo he visto varias veces cuando necesitas escribir algo en Java 1.4 hoy en día) por ejemplo:
NSMutableArray* /*<TypeA>*/ arrayName = ....
o
NSDictionary* /*<TypeA, TypeB>*/ dictionaryName = ...
Solo quiero entrar aquí. He escrito una publicación de blog aquí sobre Generics.
Lo que quiero aportar 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 a una variedad de clases, ya que funcionan exactamente igual que las colecciones de Apple. es decir. tiempo de compilación, finalización del código, lo que permite la eliminación de moldes, etc.
Disfrutar.
Esto fue lanzado en Xcode 7 (¡finalmente!)
Tenga en cuenta que en el código de Objective C, solo se trata de una verificación en tiempo de compilación; no habrá error en tiempo de ejecución solo por poner el tipo incorrecto en una colección o asignarlo a una propiedad mecanografiada.
Declarar:
@interface FooClass <T> : NSObject
@property (nonatomic) T prop;
@end
Utilizar:
FooClass<NSString *> *foo = [[FooClass alloc] init];
NSArray<FooClass<NSString *> *> *fooAry = [NSArray array];
Tenga cuidado con esos *
s.