objective c - ¿Por qué la propiedad row de NSIndexPath es un entero con signo?
objective-c ios6 (3)
¿Qué pasa si usas números negativos?
No es prudente usar valores negativos, si lo haces, obtendrás resultados locos
NSIndexPath* path = [NSIndexPath indexPathForRow:-2 inSection:0];
Lo anterior da como resultado una sección de 0 y una fila de 4294967294 (¡que me parece un NSUInteger
de un NSUInteger
para mí!) Tenga la seguridad de que esto solo ocurre dentro de la categoría de Adiciones de UIKit, y no dentro de NSIndexPath. Mirando el concepto detrás de NSIndexPath
, realmente no tiene sentido mantener valores negativos. ¿Entonces por qué?
(Posible) Razón por la cual es así.
El objeto central NSIndexPath
de OS X usa NSUInteger
s para sus índices, pero el UIKit Addition usa NSInteger
. La categoría solo se basa en el objeto central, pero el uso de NSInteger
sobre NSUInteger
no proporciona ninguna capacidad adicional.
Por qué funciona de esta manera, no tengo ni idea. Mi conjetura (y la estipulo conjetura ), es que fue un error de API ingenuo cuando se lanzó por primera vez iOS. Cuando se lanzó UITableView
en iOS 2, usó NSInteger
s para una variedad de cosas (como numberOfSections
). Piénselo: este concepto no tiene sentido, no puede tener un número negativo de secciones. Ahora, incluso en iOS 6, todavía usa NSInteger
, por lo que no rompe la compatibilidad de la aplicación anterior con las vistas de tabla.
Junto a UITableView
, tenemos las adiciones a NSIndexPath
, que se utilizan junto con la vista de tabla para acceder a sus filas y tal. Debido a que tienen que trabajar juntos, necesitan tipos compatibles (en este caso NSInteger
).
Cambiar el tipo a NSUInteger
todos los ámbitos rompería muchas cosas, y para un diseño de API seguro, sería necesario cambiar todo el nombre para que las contrapartes NSInteger y NSUInteger puedan trabajar de forma segura lado a lado. Es probable que Apple no quiera esta molestia (¡ni tampoco los desarrolladores!), Y como tal, se la han mantenido en NSInteger
.
¿Por qué la propiedad row de NSIndexPath es un entero con signo?
¿Podría alguna vez tomar un valor negativo "válido"?
editar
No he pensado en esto hasta hoy cuando configuré LLVM para verificar la comparación de signos. Esto hizo que el compilador arrojara advertencias cuando existía indexPath.row <= [someArray count]
o similar.
Creo que UIKit Additions en NSIndexPath
usa el tipo NSInteger
intencionalmente. Si, por algún motivo, la fila negativa se pasara como parameter
a cualquier método (no veo ninguno en este momento, aunque ...), el valor del NSIntegerMax + parameter
no pasará automáticamente y cualquier objeto posible no buscará un parámetro ridículamente grande que no existe. Sin embargo, hay otras formas de prevenir esto, por lo que podría ser solo una cuestión de gustos.
Yo, por ejemplo, no tomaría NSUInteger
como parámetros en la clase NSIndexPath
, sino NSInteger
y NSIndexPath
un signo y no crearía NSIndexPath
en absoluto, si algún parámetro fuera negativo.
Una posible razón es que los tipos sin firma se desbordan muy fácilmente. Como ejemplo, tenía una variable NSUInteger
para el ancho de trazo en mi código. Necesitaba crear un "sobre" alrededor de un punto pintado con este trazo, de ahí este código:
NSUInteger width = 3;
CGRect envelope = CGRectInset(CGRectZero, -width, -width);
NSLog(@"%@", NSStringFromCGRect(envelope));
Con un tipo sin signo, esto genera {{inf, inf}, {0, 0}}
, con un entero con signo obtiene {{-3, -3}, {6, 6}}
. La razón es que el menos unario antes de la variable de width
crea un subflujo. Esto puede ser obvio para alguien, pero sorprenderá a muchos programadores:
NSUInteger a = -1;
NSUInteger b = 1;
NSLog(@"a: %u, b: %u", a, -b); // a: 4294967295, b: 4294967295
Por lo tanto, incluso en situaciones en las que no tiene sentido usar un valor negativo (el ancho del trazo no puede ser negativo) tiene sentido usar el valor en un contexto negativo, lo que provoca un desbordamiento. El cambio a un tipo firmado conlleva menos sorpresas, a la vez que mantiene el rango razonablemente alto. Suena como un buen compromiso.