Một typedef enum trong Objective-C là gì?


1087

Tôi không nghĩ rằng về cơ bản tôi hiểu thế nào là một cái gì enumvà khi nào nên sử dụng nó.

Ví dụ:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Điều gì thực sự được tuyên bố ở đây?


2
Là loại người dùng xác định được gọi là "enum"? Đó là những gì tôi đã nghĩ, cho đến khi tôi bắt gặp mã có nhiều khai báo typedef enum.
Craig

8
Không, loại do người dùng xác định là ShapeType. Đọc trên typedef: en.wikipedia.org/wiki/Typedef
hung hăng

6
Một typedef trong Objective-C hoàn toàn giống với một typedef trong C. Và một enum trong Objective-C hoàn toàn giống như một enum trong C. Điều này tuyên bố một enum có ba hằng số kCircle = 0, kRonymous = 1 và kOblateSpheroid = 2 và đặt tên kiểu enum là ShapeType. Nếu bạn không biết "typedef" và "enum" nghĩa là gì, hãy mua một cuốn sách về C.
gnasher729

Câu trả lời:


1565

Ba điều đang được tuyên bố ở đây: một kiểu liệt kê vô danh được khai báo, ShapeTypeđã được tuyên bố một typedef cho rằng liệt kê vô danh, và ba tên kCircle, kRectanglekOblateSpheroidđang được khai báo là hằng số không thể thiếu.

Hãy phá vỡ nó. Trong trường hợp đơn giản nhất, một bảng liệt kê có thể được khai báo là

enum tagname { ... };

Điều này tuyên bố một bảng liệt kê với thẻ tagname. Trong C và Objective-C (nhưng không phải C ++), bất kỳ tài liệu tham khảo nào về điều này phải được đi trước với enumtừ khóa. Ví dụ:

enum tagname x;  // declare x of type 'enum tagname'
tagname x;  // ERROR in C/Objective-C, OK in C++

Để tránh phải sử dụng enumtừ khóa ở mọi nơi, một typedef có thể được tạo:

enum tagname { ... };
typedef enum tagname tagname;  // declare 'tagname' as a typedef for 'enum tagname'

Điều này có thể được đơn giản hóa thành một dòng:

typedef enum tagname { ... } tagname;  // declare both 'enum tagname' and 'tagname'

Và cuối cùng, nếu chúng ta không cần để có thể sử dụng enum tagnamevới enumtừ khóa, chúng tôi có thể làm cho enumvô danh và chỉ khai báo nó với tên typedef:

typedef enum { ... } tagname;

Bây giờ, trong trường hợp này, chúng tôi tuyên bố ShapeTypelà một tên được đánh máy của một bảng liệt kê ẩn danh. ShapeTypethực sự chỉ là một loại không thể thiếu, và chỉ nên được sử dụng để khai báo các biến mà giữ một trong các giá trị được liệt kê trong phần khai báo (có nghĩa là, một trong những kCircle, kRectanglekOblateSpheroid). Tuy nhiên, bạn có thể gán một ShapeTypebiến khác một giá trị bằng cách truyền, vì vậy bạn phải cẩn thận khi đọc các giá trị enum.

Cuối cùng, kCircle, kRectangle, và kOblateSpheroidđược khai báo là hằng số không thể thiếu trong không gian tên toàn cầu. Vì không có giá trị cụ thể nào được chỉ định, chúng được gán cho các số nguyên liên tiếp bắt đầu bằng 0, do đó kCirclelà 0, kRectanglelà 1 và kOblateSpheroidlà 2.


6
Giải thích hay - chỉ cần thêm một điều, struct tuân theo các quy tắc đặt tên tương tự trong C (không chắc chắn về Objective-C).
Michael Burr

109
Objective-C là một superset thích hợp của C. Tất cả các quy tắc đặt tên cấu trúc C trong C đều có giá trị trong Objective-C.
sigjuice

Tuyệt vời. Tôi có thể chỉ sử dụng enum kiểu C ++ và cũng không cần phải viết enum :)
user4951

11
Bạn có thể sử dụng enum kiểu C ++ nếu tệp mà bạn khai báo là tệp .mm chứ không phải là .m. Objective-C ++ có sức mạnh phi lý.
Kevin Hoffman

14
Và một khi bạn đã hiểu được câu trả lời này, thật đáng để xem NS_ENUM và NS_OPTIONS mới. Hướng dẫn tại đây: nshipster.com/ns_enum-ns_options và SO tại đây: stackoverflow.com/questions/14080750/ chủ
Snowcrash

254

Apple khuyên bạn nên xác định enums như thế này kể từ Xcode 4.4 :

typedef enum ShapeType : NSUInteger {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Họ cũng cung cấp một macro tiện dụng NS_ENUM:

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

Các định nghĩa này cung cấp kiểm tra loại mạnh hơn và hoàn thành mã tốt hơn. Tôi không thể tìm thấy tài liệu chính thức về NS_ENUM, nhưng bạn có thể xem video "Modern Objective-C" từ phiên WWDC 2012 tại đây .


CẬP NHẬT
Liên kết đến tài liệu chính thức ở đây .


13
Phần về "Cải tiến Enum" bắt đầu lúc 5:58
vikingosegundo

5
Như đã nhận xét về một câu trả lời khác, hãy xem giải thích về NS_ENUMmacro của Apple bởi NSHipster: NSHipster.com/ns_enum-ns_options
Basil Bourque

1
Đây là liên kết đến tài liệu chính thức về NS_ENUM: developer.apple.com/l
Library / ios / releasenotes / OcjectiveC / giả

50

Một enum tuyên bố một tập hợp các giá trị được sắp xếp - typedef chỉ cần thêm một tên tiện dụng cho cái này. Phần tử thứ 1 là 0, v.v.

typedef enum {
Monday=1,
...
} WORKDAYS;

WORKDAYS today = Monday;

Trên đây chỉ là một bảng liệt kê các thẻ shapeType.


34

Một người sử dụng định nghĩa kiểu đó có các giá trị có thể có của kCircle, kRectanglehoặc kOblateSpheroid. Tuy nhiên, các giá trị bên trong enum (kCircle, v.v.) có thể nhìn thấy bên ngoài enum. Điều quan trọng là phải ghi nhớ điều đó ( int i = kCircle;ví dụ: hợp lệ).


30

Cập nhật thay đổi 64 bit: Theo tài liệu của apple về các thay đổi 64 bit,

Số liệt kê cũng được gõ: Trong trình biên dịch LLVM, các kiểu liệt kê có thể xác định kích thước của bảng liệt kê. Điều này có nghĩa là một số loại liệt kê cũng có thể có kích thước lớn hơn bạn mong đợi. Giải pháp, như trong tất cả các trường hợp khác, là không đưa ra giả định nào về kích thước của loại dữ liệu. Thay vào đó, gán bất kỳ giá trị liệt kê nào cho một biến có kiểu dữ liệu phù hợp

Vì vậy, bạn phải tạo enum với kiểu cú pháp dưới đây nếu bạn hỗ trợ 64-bit.

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

hoặc là

typedef enum ShapeType : NSUInteger {
   kCircle,
   kRectangle,
   kOblateSpheroid
} ShapeType;

Nếu không, nó sẽ dẫn đến cảnh báo như Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

Cập nhật cho lập trình nhanh chóng:

Trong swift, có một sự thay đổi cú pháp.

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }

Nếu cần thiết phải về phía trước khai báo enum (NS_ENUM): stackoverflow.com/a/42009056/342794
lal

25

Enum (viết tắt của phép liệt kê) được sử dụng để liệt kê một tập hợp các giá trị (liệt kê). Giá trị là một thứ trừu tượng được biểu thị bằng một ký hiệu (một từ). Ví dụ, một enum cơ bản có thể là

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };

Enum này được gọi là ẩn danh vì bạn không có ký hiệu để đặt tên cho nó. Nhưng nó vẫn hoàn toàn chính xác. Chỉ cần sử dụng nó như thế này

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;

Đồng ý. Cuộc sống thật đẹp và mọi thứ đều suôn sẻ. Nhưng một ngày nào đó bạn cần sử dụng lại enum này để xác định một biến mới để lưu trữ myGrandFatherPantSize, sau đó bạn viết:

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;

Nhưng sau đó, bạn có một lỗi biên dịch "xác định lại của điều tra viên". Trên thực tế, vấn đề là trình biên dịch không chắc chắn rằng bạn là enum đầu tiên và bạn là người thứ hai mô tả điều tương tự.

Sau đó, nếu bạn muốn sử dụng lại cùng một bộ liệt kê (ở đây xs ... xxxxl) ở một số nơi, bạn phải gắn thẻ nó với một tên duy nhất. Lần thứ hai bạn sử dụng bộ này, bạn chỉ cần sử dụng thẻ. Nhưng đừng quên rằng thẻ này không thay thế từ enum mà chỉ là bộ liệt kê. Sau đó hãy cẩn thận để sử dụng enum như bình thường. Như thế này:

// Here the first use of my enum
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize; 
// here the second use of my enum. It works now!
enum sizes myGrandFatherPantSize;

bạn cũng có thể sử dụng nó trong một định nghĩa tham số:

// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;

Bạn có thể nói rằng viết lại enum ở mọi nơi không thuận tiện và làm cho mã trông hơi lạ. Bạn đúng rồi. Một loại thực sự sẽ tốt hơn.

Đây là bước cuối cùng của sự tiến bộ vĩ đại của chúng tôi đến hội nghị thượng đỉnh. Chỉ cần thêm một typedef, hãy biến enum của chúng ta thành một kiểu thực. Ồ, điều cuối cùng, typedef không được phép trong lớp của bạn. Sau đó xác định loại của bạn ở trên. Làm như thế này:

// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type

@interface myClass {
   ...
   size_type myGrandMotherDressSize, myGrandFatherPantSize;
   ...
}

Hãy nhớ rằng thẻ là tùy chọn. Sau đó, trong trường hợp đó, chúng tôi không gắn thẻ cho các điều tra viên mà chỉ để xác định một loại mới. Sau đó, chúng tôi không thực sự cần nó nữa.

// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;

@interface myClass : NSObject {
  ...
  size_type myGrandMotherDressSize, myGrandFatherPantSize;
  ...
}
@end

Nếu bạn đang phát triển trong Objective-C với XCode, tôi sẽ cho phép bạn khám phá một số macro đẹp có tiền tố NS_ENUM. Điều đó sẽ giúp bạn xác định các enum tốt một cách dễ dàng và hơn nữa sẽ giúp bộ phân tích tĩnh thực hiện một số kiểm tra thú vị cho bạn trước khi biên dịch.

Tốt Enum!


Tôi luôn nghĩ rằng "tại sao mọi người sẽ trả lời một câu hỏi đã được trả lời và chấp nhận". Chàng trai, tôi đã sai mọi lúc! Đây là câu trả lời tốt nhất và giúp những người mới bắt đầu như tôi!
rak appdev

10

typedefrất hữu ích để xác định lại tên của một loại biến hiện có. Nó cung cấp cách ngắn gọn và có ý nghĩa để gọi một kiểu dữ liệu. ví dụ:

typedef unsigned long int TWOWORDS;

ở đây, kiểu int unsign dài được xác định lại là kiểu TWOWORDS. Vì vậy, bây giờ chúng ta có thể khai báo các biến kiểu không dấu int dài bằng cách viết,

TWOWORDS var1, var2;

thay vì

unsigned long int var1, var2;

7
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

sau đó bạn có thể sử dụng nó như: -

 ShapeType shape;

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

bây giờ bạn có thể sử dụng nó như: -

enum ShapeType shape;

3

enum được sử dụng để gán giá trị cho các phần tử enum không thể thực hiện được trong struct. Vì vậy, mọi lúc thay vì truy cập vào biến hoàn chỉnh, chúng ta có thể thực hiện nó bằng giá trị chúng ta gán cho các biến trong enum. Theo mặc định, nó bắt đầu bằng phép gán 0 nhưng chúng ta có thể gán cho nó bất kỳ giá trị nào và biến tiếp theo trong enum sẽ được gán một giá trị giá trị +1 trước đó.


3

Bạn có thể sử dụng ở định dạng bên dưới, Giá trị mặc định thô bắt đầu từ 0, vì vậy

  • kCircle là 0,
  • Hình chữ nhật là 1,
  • kOblateSpheroid là 2.

Bạn có thể chỉ định giá trị bắt đầu cụ thể của riêng bạn.

typedef enum : NSUInteger {
    kCircle, // for your value; kCircle = 5, ...
    kRectangle,
    kOblateSpheroid
} ShapeType;

ShapeType circleShape = kCircle;
NSLog(@"%lu", (unsigned long) circleShape); // prints: 0

2

Một typedef cho phép lập trình viên xác định một loại Objective-C là một loại khác. Ví dụ,

typedef int Counter; định nghĩa kiểu Counter tương đương với kiểu int. Điều này cải thiện đáng kể khả năng đọc mã.


2

Typedef là một từ khóa trong C và C ++. Nó được sử dụng để tạo tên mới cho các kiểu dữ liệu cơ bản (char, int, float, double, struct & enum) .

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

Ở đây, nó tạo ra kiểu dữ liệu liệt kê ShapeType & chúng ta có thể viết tên mới cho kiểu enum ShapeType như được đưa ra dưới đây

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;

1

enum có thể giảm nhiều loại "lỗi" và làm cho mã dễ quản lý hơn

#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER

Định nghĩa không có ràng buộc. Nó chỉ đơn giản là một sự thay thế. Nó không thể giới hạn tất cả các điều kiện của nhà nước. Khi STATE được gán cho 5, chương trình sẽ sai, vì không có trạng thái khớp. Nhưng trình biên dịch sẽ không cảnh báo STATE = 5

Vì vậy, tốt hơn là sử dụng như thế này

typedef enum SampleState {
    SampleStateGood  = 0,
    SampleStateBad,
    SampleStateOther
} SampleState;

SampleState state = SampleStateGood;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.