significado que pelicula mucho fuerzo fuerza fuerces fuercen fuerce forzo forzar forza forces force define cómo correcto objective-c cocoa nsmutablearray

objective-c - pelicula - que es correcto fuerces o forces



NSMutableArray: fuerce la matriz para mantener solo el tipo de objeto específico (12)

¡Con los genéricos XCode 7 ahora están disponibles en Objective-C!

Entonces puede declarar su NSMutableArray como:

NSMutableArray <Wheel*> *wheels = [[NSMutableArray alloc] initWithArray:@[[Wheel new],[Wheel new]];

El compilador le dará una advertencia si intenta colocar objetos que no sean Wheel en su matriz.

¿Hay alguna manera de forzar NSMutableArray para que contenga un solo tipo de objeto específico?

Tengo definiciones de clases de la siguiente manera:

@interface Wheel:NSObject { int size; float diameter; } @end @interface Car:NSObject { NSString *model; NSString *make; NSMutableArray *wheels; } @end

¿Cómo puedo forzar que la matriz de ruedas mantenga los objetos de rueda solo con el código? (y absolutamente no otros objetos)


Aquí hay algo que he hecho para evitar la subclasificación de NSMutableArray: usar una categoría. De esta forma, puede tener el argumento y los tipos de devolución que desee. Tenga en cuenta la convención de nomenclatura: reemplace la palabra "objeto" en cada uno de los métodos que usará con el nombre de la clase de elemento. "objectAtIndex" se convierte en "wheelAtIndex" y así sucesivamente. De esta manera no hay conflicto de nombre. Muy ordenado.

typedef NSMutableArray WheelList; @interface NSMutableArray (WheelList) - (wheel *) wheelAtIndex: (NSUInteger) index; - (void) addWheel: (wheel *) w; @end @implementation NSMutableArray (WheelList) - (wheel *) wheelAtIndex: (NSUInteger) index { return (wheel *) [self objectAtIndex: index]; } - (void) addWheel: (wheel *) w { [self addObject: w]; } @end @interface Car : NSObject @property WheelList *wheels; @end; @implementation Car @synthesize wheels; - (id) init { if (self = [super init]) { wheels = [[WheelList alloc] initWithCapacity: 4]; } return self; } @end


Eso no es posible; un NSArray (ya sea mutable o no) contendrá cualquier tipo de objeto. Lo que puedes hacer es crear tus propias subclases personalizadas como ya sugirió Jim. Alternativamente, si desea filtrar una matriz para eliminar objetos que no son del tipo que desea, entonces podría hacer:

- (void)removeObjectsFromArray:(NSMutableArray *)array otherThanOfType:(Class)type { int c = 0; while(c < [array length]) { NSObject *object = [array objectAtIndex:c]; if([object isKindOfClass:type]) c++; else [array removeObjectAtIndex:c]; } } ... [self removeObjectsFromArray:array otherThanOfType:[Car class]];

O haga otros juicios basados ​​en el resultado de isKindOfClass :, por ejemplo, para dividir una matriz que contenga una mezcla de Cars y Wheels en dos matrices, cada una con un solo tipo de objeto.


Espero que esto ayude (y funcione ...: P)

Archivo Wheel.h :

@protocol Wheel @end @interface Wheel : NSObject @property ... @end

Archivo Car.h :

#import "Wheel.h" @interface Car:NSObject { NSString *model; NSString *make; NSMutableArray<Wheel, Optional> *wheels; } @end

Archivo Car.m :

#import "Car.h" @implementation Car -(id)init{ if (self=[super init]){ self.wheels = (NSMutableArray<Wheel,Optional>*)[NSMutableArray alloc]init]; } return self; } @end


Hay un proyecto de archivo de un encabezado que permite esto: Objective-C-Generics

Uso :

Copie ObjectiveCGenerics.h a su proyecto. Al definir una nueva clase, use la macro GENERICSABLE.

#import "ObjectiveCGenerics.h" GENERICSABLE(MyClass) @interface MyClass : NSObject<MyClass> @property (nonatomic, strong) NSString* name; @end

Ahora puede usar genéricos con matrices y conjuntos tal como lo hace normalmente en Java, C #, etc.

Código:


No creo que haya ninguna manera de hacerlo con NSMutableArray fuera de la caja. Probablemente puedas aplicar esto subclasificando y anulando todos los constructores y métodos de inserción, pero probablemente no valga la pena. ¿Qué esperas lograr con esto?


Podría estar equivocado (soy novato), pero creo que si crea un protocolo personalizado y se asegura de que los objetos que está agregando a la matriz sigan el mismo protocolo, cuando declare la matriz que utiliza

NSArray<Protocol Name>

Eso debería evitar que se agreguen objetos que no siguen dicho protocolo.


Puedes usar nsexception si no tienes el objeto específico.

for (int i = 0; i<items.count;i++) { if([[items objectAtIndex:i] isKindOfClass:[Wheel class]]) { // do something..! }else{ [NSException raise:@"Invalid value" format:@"Format of %@ is invalid", items]; // do whatever to handle or raise your exception. } }


Xcode 7 le permite definir matrices, diccionarios e incluso sus propias clases con genéricos. La sintaxis de matriz es la siguiente:

NSArray<NSString*>* array = @[@"hello world"];


como sé ... antes de agregar cualquier objeto en ruedas mutableArray, tienes que agregar alguna marca de verificación. Es el objeto que estoy agregando es clase "rueda". si es entonces, añada, de lo contrario, no.

Ejemplo:

if([id isClassOf:"Wheel"] == YES) { [array addObject:id) }

Algo como esto. No recuerdo la sintaxis exacta.


protocolo tal vez una buena idea:

@protocol Person <NSObject> @end @interface Person : NSObject <Person> @end

usar:

NSArray<Person>* personArray;


Actualización en 2015

Esta respuesta se escribió por primera vez a principios de 2011 y comenzó:

Lo que realmente queremos es un polimorfismo paramétrico para poder declarar, por ejemplo, NSMutableArray<NSString> ; pero, por desgracia, no está disponible.

En 2015, Apple aparentemente cambió esto con la introducción de "genéricos ligeros" en Objective-C y ahora puedes declarar:

NSMutableArray<NSString *> *onlyStrings = [NSMutableArray new];

Pero no todo es lo que parece, observe el "peso ligero" ... Luego observe que la parte de inicialización de la declaración anterior no contiene ninguna notación genérica. Mientras que Apple ha introducido colecciones paramétricas, y agrega una cadena no directamente a la matriz anterior, onlyStrings , como en decir:

[onlyStrings addObject:@666]; // <- Warning: Incompatible pointer types...

ilícita la advertencia como se indica, el tipo de seguridad es apenas superficial. Considera el método:

- (void) push:(id)obj onto:(NSMutableArray *)array { [array addObject:obj]; }

y el fragmento de código en otro método de la misma clase:

NSMutableArray<NSString *> *oops = [NSMutableArray new]; [self push:@"asda" onto:oops]; // add a string, fine [self push:@42 onto:oops]; // add a number, no warnings...

Lo que Apple ha implementado es esencialmente un sistema de sugerencias para ayudar con la interacción automática con Swift, que tiene un sabor de genéricos seguros para tipos. Sin embargo, en el lado de Objective-C, aunque el compilador proporciona algunas pistas adicionales, el sistema es "liviano" y la integridad del tipo aún depende del programador, al igual que el método Objective-C.

Entonces, ¿cuál deberías usar? Los nuevos ligeros / pseudo genéricos, o idear sus propios patrones para su código? Realmente no hay una respuesta correcta, averigüe qué tiene sentido en su escenario y úselo.

Por ejemplo: si tiene como objetivo la interoperación con Swift, debe usar los genéricos ligeros. Sin embargo, si la integridad de tipo de una colección es importante en su escenario, entonces podría combinar los genéricos ligeros con su propio código en el lado de Objective-C, que impone la integridad de tipo que Swift tendrá de lado.

El resto de la respuesta de 2011

Como otra opción aquí hay una subclase general rápida de NSMutableArray que inicia con el tipo de objeto que desea en su matriz monomórfica. Esta opción no le proporciona comprobación de tipos estática (en la medida en que la obtenga en Obj-C), obtiene excepciones de tiempo de ejecución al insertar el tipo incorrecto, del mismo modo que obtiene excepciones de tiempo de ejecución para índices fuera de límites, etc.

Esto no se ha probado exhaustivamente y supone que la documentación sobre la anulación de NSMutableArray es correcta ...

@interface MonomorphicArray : NSMutableArray { Class elementClass; NSMutableArray *realArray; } - (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems; - (id) initWithClass:(Class)element; @end

Y la implementación:

@implementation MonomorphicArray - (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems { elementClass = element; realArray = [NSMutableArray arrayWithCapacity:numItems]; return self; } - (id) initWithClass:(Class)element { elementClass = element; realArray = [NSMutableArray new]; return self; } // override primitive NSMutableArray methods and enforce monomorphism - (void) insertObject:(id)anObject atIndex:(NSUInteger)index { if ([anObject isKindOfClass:elementClass]) // allows subclasses, use isMemeberOfClass for exact match { [realArray insertObject:anObject atIndex:index]; } else { NSException* myException = [NSException exceptionWithName:@"InvalidAddObject" reason:@"Added object has wrong type" userInfo:nil]; @throw myException; } } - (void) removeObjectAtIndex:(NSUInteger)index { [realArray removeObjectAtIndex:index]; } // override primitive NSArray methods - (NSUInteger) count { return [realArray count]; } - (id) objectAtIndex:(NSUInteger)index { return [realArray objectAtIndex:index]; } // block all the other init''s (some could be supported) static id NotSupported() { NSException* myException = [NSException exceptionWithName:@"InvalidInitializer" reason:@"Only initWithClass: and initWithClass:andCapacity: supported" userInfo:nil]; @throw myException; } - (id)initWithArray:(NSArray *)anArray { return NotSupported(); } - (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { return NotSupported(); } - (id)initWithContentsOfFile:(NSString *)aPath { return NotSupported(); } - (id)initWithContentsOfURL:(NSURL *)aURL { return NotSupported(); } - (id)initWithObjects:(id)firstObj, ... { return NotSupported(); } - (id)initWithObjects:(const id *)objects count:(NSUInteger)count { return NotSupported(); } @end

Usar como:

MonomorphicArray *monoString = [[MonomorphicArray alloc] initWithClass:[NSString class] andCapacity:3]; [monoString addObject:@"A string"]; [monoString addObject:[NSNumber numberWithInt:42]]; // will throw [monoString addObject:@"Another string"];