В чем разница между
typedef enum {
...
} Name;
и
enum {
...
};
typedef NSUInteger Name;
? Если функциональность одинакова, для чего нужна вторая форма? Разве это бесполезно грязно?
В чем разница между
typedef enum {
...
} Name;
и
enum {
...
};
typedef NSUInteger Name;
? Если функциональность одинакова, для чего нужна вторая форма? Разве это бесполезно грязно?
enum
стареет как C
, поэтому является частью Objective-C
.
Это просто явное кодирование типа int
. Это очень полезно для отладки, и большинство новых компиляторов могут сделать на нем оптимизацию. (Который вы должны полностью игнорировать). Это наиболее полезно для того, чтобы сделать ваш код более читаемым (кому-либо другому или самому себе после того, как вы спали).
typedef enum {
...
} NameType ;
будет следовать
NameType name;
и обычно типичный стиль typedef,
ваш второй пример будет не привязать typedef к значениям, которые вы хотите указать, должен быть только данного типа.
Обратите внимание, что это не мешает вам выполнять
name = 10244; // some non-valid value not listed in the enumeration
но некоторые компиляторы могут генерировать предупреждение в этом случае,
Я воспользовался следующим использованием Apple сегодня:
enum {
NSFetchedResultsChangeInsert = 1,
NSFetchedResultsChangeDelete = 2,
NSFetchedResultsChangeMove = 3,
NSFetchedResultsChangeUpdate = 4
};
typedef NSUInteger NSFetchedResultsChangeType;
Они делают это, потому что они действительно хотят, чтобы NSFetchedResultsChangeType
был того типа, который они определили как NSUInteger
. Это может быть int
, но это может быть и другое. И со значениями 1, 2, 3 и 4 это несколько не имеет отношения к нам, что такое тип. Но они кодируют другой уровень абстракции, потому что они являются поставщиками инструментов.
Вы не должны смотреть на Apple для подсказок стиля кодирования. Если вы видите что-то похожее на более чистый/лучший способ кодирования, это обычно так. Как отметил Кевин, устойчивость API для них имеет первостепенное значение.
Изменить (январь 2013 г.). Если у вас есть доступ к видеозаписям WWDC 2012, вы должны смотреть Session 405 - Modern Objective-C
6: 00-10: 00. В новом компиляторе обсуждается новый синтаксис, который позволяет явно определять размер и тесно связывать значения с типами. (заимствован из С++ 11)
enum NSFetchedResultsChangeType : NSUInteger {
NSFetchedResultsChangeInsert = 1,
NSFetchedResultsChangeDelete = 2,
NSFetchedResultsChangeMove = 3,
NSFetchedResultsChangeUpdate = 4
};
Первый определяет имя типа для ссылки на перечисление. Это то, как большинство имен перечислены в C. Последнее немного отличается, и оно распространено в рамках Cocoa. Есть две причины использовать последний. Во-первых, если ваше перечисление определяет бит поля, и вы хотите его здесь, потому что, когда вы предоставляете значение "Имя", вы будете предоставлять комбинацию значений перечисления. Другими словами, если вы скажете что-то вроде
[self doSomethingWithBitfield:(Enum1 | Enum2)]
вы не передаете значение Name, а целое число, состоящее из комбинации двух.
Однако фреймворки Cocoa используют эту идиому даже для значений, отличных от битового поля, по очень хорошей причине: стабильность API. Согласно стандарту C, базовый интегральный тип перечисления должен иметь возможность содержать все значения в перечислении, но в противном случае выбран компилятором. Это означает, что добавление нового значения перечисления может изменить интегральный тип перечисления (например, добавление -1 может сделать его подписанным, добавив, что 6 миллиардов могут сделать его длинным и т.д.). Это плохо с точки зрения устойчивости API, потому что тип кодирования методов, которые принимают значения этого перечисления, может неожиданно измениться и потенциально нарушить существующий код и двоичные файлы. Чтобы предотвратить это, инфраструктура Cocoa обычно определяет тип как NSUInteger (или NSInteger, если они нуждаются в отрицательных числах), поэтому кодировки API и типа остаются стабильными.