NSSet of NSNumbers: el método de miembro es siempre nulo


Quiero tener un NSSet simple que esté cargado con algunos NSNumbers y luego averiguar si esos números ya están agregados en el conjunto o no. Cuando hago esto:

NSMutableSet *set = [[NSMutableSet alloc] init];
NSNumber *num1 = [NSNumber numberWithInt:5];
NSNumber *num2 = [NSNumber numberWithInt:5];
[set addObject:num1];
if([set member:num2]){
   // something...
}

El problema es que el miembro siempre devuelve nil (si es falso), incluso si esos números son los mismos. El método isEqual devuelve verdadero. Entonces

if([num1 isEqual:num2]){
   // correct
}

trabajos...
En los documentos, leí que el método de miembro usa isEqual, así que no sé cuál es el problema ... Gracias por cualquier consejo.

preguntado el 08 de noviembre de 11 a las 14:11

si su código está pegado correctamente, no agregó el objeto num2 a su conjunto,

¿Estás seguro ... tu código funciona perfectamente bien para mí! -

@Maggie sí, estoy seguro, el punto es que quiero verificar si el número 5 ya está en el conjunto, pero tengo que usar nsnumber porque son objetos, así que quiero verificar si el objeto nsnumber con valor de 5 ya está en el conjunto (num1 con valor 5 es, por lo que debería devolver verdadero) -

@Miraaj bueno, lo copié de xcode e hizo lo que describí ... No estoy muy seguro de por qué -

4 Respuestas

Cuando utiliza NSArray, debe comparar los valores en lugar de los objetos en sí. En lugar de utilizar NSArray, puede utilizar NSMutableIndexSet. Esto le permite comparar los valores con unos pocos pasos menos.

//during init, add some numbers
NSMutableIndexSet *tSet = [[NSMutableIndexSet alloc] init];
NSUInteger exampleValue = 7;
[tSet addIndex:exampleValue];
exampleValue = 42;
[tSet addIndex:exampleValue];

//...later on
//look to see if numbers are there
if ([tSet containsIndex:7]){
    NSLog(@"7 exists!");
}
if ([tSet containsIndex:8]){
    NSLog(@"8 exists!");
}

Salida: ¡7 existe!

Respondido el 11 de junio de 15 a las 03:06

Es necesario comparar los valores de NSNumbers, no los objetos.

Puedes usar objectsPassingTest:

Ejemplo:

NSMutableSet *set = [[NSMutableSet alloc] init];
NSNumber *num1 = [NSNumber numberWithInt:5];
NSNumber *num2 = [NSNumber numberWithInt:5];
NSNumber *num3 = [NSNumber numberWithInt:3];
[set addObject:num1];

NSSet *filteredSet;
filteredSet = [set objectsPassingTest:^(id obj,BOOL *stop){
    return [obj isEqualToNumber:num2];
}];
NSLog(@"Contains num2: %@", (filteredSet.count == 1) ? @"YES" : @"NO");

filteredSet = [set objectsPassingTest:^(id obj,BOOL *stop){
    return [obj isEqualToNumber:num3];
}];
NSLog(@"Contains num3: %@", (filteredSet.count == 1) ? @"YES" : @"NO");

Salida NSLog:

Contains num2: YES
Contains num3: NO

O si se desea usar predicados:

filteredSet = [set filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"SELF == %@", num2]];
NSLog(@"Contains num2: %@", (filteredSet.count == 1) ? @"YES" : @"NO");

filteredSet = [set filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"SELF == %@", num3]];
NSLog(@"Contains num3: %@", (filteredSet.count == 1) ? @"YES" : @"NO");

respondido 08 nov., 11:20

El problema es que está comprobando si num1 y num2 son el mismo objeto. Y no lo son. Simplemente tienen el mismo valor pero son dos objetos diferentes con el mismo valor.

Entonces, ¿con qué estás comprobando? member es si tienen la misma dirección en la memoria.

Editar: deberías usar compare para comprobar si los valores de los números son los mismos!

respondido 08 nov., 11:18

"si tienen la misma dirección en la memoria" es falso; de acuerdo con la member: docs: "Si el conjunto contiene un objeto igual a objeto (según lo determinado por isEqual :) entonces ese objeto (normalmente será un objeto), de lo contrario nil." - Wevah

Ambos podrían tener razón ... Creo recordar que NSNumber tiene una optimización engañosa en la que tiene representaciones estáticas de los primeros números enteros. En este caso, la dirección de memoria y isEqual funcionaría. - jrturton

Seguro, pero no debería devolver falso de ninguna manera. - Wevah

Podría usar el método de comparación para comparar 2 NSNumbers, pero quiero verificar si 1 NSNumber está en el conjunto de NSNumbers, así que debería recorrer el conjunto y verificar 1 por 1 o hay algún otro método que realmente funcione como se describe en los documentos ? - haluzak

El código funciona desde Hola palabra está escrito en el registro cuando lo ejecuto

 NSMutableSet *set = [[NSMutableSet alloc] init];
 NSNumber *num1 = [NSNumber numberWithInt:5];
 NSNumber *num2 = [NSNumber numberWithInt:5];
 [set addObject:num1];
 if([set member:num2]){
     NSLog(@"Hello, world");
  }

Respondido 18 Jul 13, 22:07

Esto no es del todo válido ya que si cambio el valor de * num1 a 6 después de haberlo agregado al conjunto y luego pregunto si [set member num1] y [set member num2] ambos devuelven verdadero. - Ryan Heitner

@RyanHeitner, ¿Cómo se puede cambiar un objeto NSNumber? ¡Son inmutables! - ragnarius

NSNumber * num1 = [NSNumber numberWithInt: 5]; [set addObject: num1]; num1 = [NSNumber numberWithInt: 6]; - Ryan Heitner

@RyanHeitner, después de la segunda asignación, num1 apunta a un objeto completamente diferente con una dirección diferente y un contenido diferente del num1 una vez almacenado en el conjunto. - ragnarius

al usar la solución de Zaph anterior, aún obtiene los resultados esperados y con su solución obtiene (al menos para mí) un resultado inesperado. - Ryan Heitner

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.