Подтвердить что ты не робот

Enum определяет формы в Objective-C

В чем разница между

typedef enum {
    ...
} Name;

и

enum {
    ...
};
typedef NSUInteger Name;

? Если функциональность одинакова, для чего нужна вторая форма? Разве это бесполезно грязно?

4b9b3361

Ответ 1

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
};

Ответ 2

Первый определяет имя типа для ссылки на перечисление. Это то, как большинство имен перечислены в C. Последнее немного отличается, и оно распространено в рамках Cocoa. Есть две причины использовать последний. Во-первых, если ваше перечисление определяет бит поля, и вы хотите его здесь, потому что, когда вы предоставляете значение "Имя", вы будете предоставлять комбинацию значений перечисления. Другими словами, если вы скажете что-то вроде

[self doSomethingWithBitfield:(Enum1 | Enum2)]

вы не передаете значение Name, а целое число, состоящее из комбинации двух.

Однако фреймворки Cocoa используют эту идиому даже для значений, отличных от битового поля, по очень хорошей причине: стабильность API. Согласно стандарту C, базовый интегральный тип перечисления должен иметь возможность содержать все значения в перечислении, но в противном случае выбран компилятором. Это означает, что добавление нового значения перечисления может изменить интегральный тип перечисления (например, добавление -1 может сделать его подписанным, добавив, что 6 миллиардов могут сделать его длинным и т.д.). Это плохо с точки зрения устойчивости API, потому что тип кодирования методов, которые принимают значения этого перечисления, может неожиданно измениться и потенциально нарушить существующий код и двоичные файлы. Чтобы предотвратить это, инфраструктура Cocoa обычно определяет тип как NSUInteger (или NSInteger, если они нуждаются в отрицательных числах), поэтому кодировки API и типа остаются стабильными.