Почему свойство row NSIndexPath имеет целое число со знаком?
Почему свойство строки NSIndexPath имеет целое число со знаком?
Может ли это когда-либо принимать "действительное" отрицательное значение?
![enter image description here]()
изменить
Я не думал об этом до сегодняшнего дня, когда я установил LLVM для проверки сравнения знака. Это заставило компилятор извергать предупреждения всякий раз, когда был indexPath.row <= [someArray count]
или аналогичный.
Ответы
Ответ 1
Что произойдет, если вы используете отрицательные числа?
Нецелесообразно использовать отрицательные значения, если вы это сделаете, вы получите сумасшедшие результаты
NSIndexPath* path = [NSIndexPath indexPathForRow:-2 inSection:0];
Приведенные выше результаты состоят из раздела 0 и строки 4294967294 (для меня это выглядит как underflow NSUInteger
!). Будьте уверены, что это происходит только в категории UIKit Additions, а не в NSIndexPath сам. Рассматривая концепцию NSIndexPath
, на самом деле не имеет смысла удерживать отрицательные значения. Так почему?
(возможно) Причина, почему это так
Основной объект NSIndexPath
из OS X использует NSUInteger
для своих индексов, но UIKit Addition использует NSInteger
. Категория только строится поверх основного объекта, но использование NSInteger
over NSUInteger
не предоставляет никаких дополнительных возможностей.
Почему это работает так, я понятия не имею. Мое предположение (и я предугадываю предположение), это был наивный API slipup при первом запуске iOS. Когда в iOS 2 был выпущен UITableView
, он использовал NSInteger
для множества вещей (например, numberOfSections
). Подумайте об этом: это концептуально не имеет смысла, вы не можете иметь отрицательное количество разделов. Теперь даже в iOS 6 он все еще использует NSInteger
, чтобы не разорвать предыдущую совместимость приложений с представлениями таблицы.
Наряду с UITableView
у нас есть дополнения к NSIndexPath
, которые используются в сочетании с табличным представлением для доступа к ним и тому подобным. Поскольку они должны работать вместе, им нужны совместимые типы (в данном случае NSInteger
).
Чтобы изменить тип на NSUInteger
по всей доске, это сломает много вещей, и для безопасного проектирования API все нужно будет переименовать, чтобы аналоги Nabelteger и NSUInteger могли безопасно работать бок о бок. Apple, вероятно, не хочет этого хлопота (и разработчиков тоже!), И поэтому они сохранили его до NSInteger
.
Ответ 2
Одна из возможных причин заключается в том, что неподписанные типы очень легко перетекают. В качестве примера у меня была переменная NSUInteger
для ширины штриха в моем коде. Мне нужно было создать "конверт" вокруг точки, нарисованной с помощью этого штриха, поэтому этот код:
NSUInteger width = 3;
CGRect envelope = CGRectInset(CGRectZero, -width, -width);
NSLog(@"%@", NSStringFromCGRect(envelope));
При неподписанном типе это выводит {{inf, inf}, {0, 0}}
, с целым знаком, вы получаете {{-3, -3}, {6, 6}}
. Причина в том, что унарный минус перед переменной width
создает нижнее течение. Это может быть очевидно для кого-то, но удивит многих программистов:
NSUInteger a = -1;
NSUInteger b = 1;
NSLog(@"a: %u, b: %u", a, -b); // a: 4294967295, b: 4294967295
Таким образом, даже в ситуациях, когда нет смысла использовать отрицательное значение (ширина штриха не может быть отрицательной), имеет смысл использовать значение в отрицательном контексте, вызывая недоисполнение. Переход на подписанный тип приводит к меньшим неожиданностям, сохраняя при этом диапазон достаточно высоким. Похоже на хороший компромисс.
Ответ 3
Я думаю, что UIKit Дополнения на NSIndexPath
используют тип NSInteger
намеренно. Если по какой-то причине отрицательная строка будет передана как parameter
любому методу (в настоящий момент я не вижу ни одного), значение autocast до NSIntegerMax + parameter
не произойдет, и любой возможный объект не будет искать смехотворно большие параметр, который не существует. Тем не менее, есть и другие способы предотвратить это, поэтому это может быть просто вопрос вкуса.
Я, например, не принимал бы NSUInteger
в качестве параметров в классе NSIndexPath
, а скорее NSInteger
и проверял знак и вообще не создавал бы NSIndexPath
, если бы какой-либо параметр был отрицательным.