2009-07-27 38 views
23

tôi cần phải tạo ra một từ điển/hashmap nơiCa cao: Từ điển có khóa enum?

  • Keys là enums
  • giá trị là một số lớp con của NSObject

NSDictionary sẽ không làm việc ở đây (enums không phù hợp với NSCopying).

Tôi có thể sử dụng số CFDictionaryRef tại đây, nhưng tôi muốn biết liệu có cách nào khác để đạt được điều này hay không.

Trả lời

29

Vì enums là số nguyên, bạn có thể bọc enum trong một NSNumber. Khi bạn thêm/truy xuất một cái gì đó đến/từ bản đồ, bạn vượt qua enum để các nhà xây dựng NSNumber ...

Giả sử bạn đã có một enum như ...

enum ETest { 
    FOO, BAR 
}; 

Bạn có thể sử dụng nó trong một NSDictionary như thế này ...

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setObject: @"Foo!" forKey:[NSNumber numberWithInt: FOO]]; 
NSLog(@"getting value for FOO -> %@", 
     [dict objectForKey: [NSNumber numberWithInt: FOO]]); 
[dict release]; 
+0

Cảm ơn! Điều đó làm việc hoàn toàn tuyệt vời :) – PlagueHammer

7

enums don't conform to NSCopying

Đây là một cách nói giảm; enums không "phù hợp" với bất kỳ thứ gì vì chúng không phải là vật thể; chúng là các giá trị C nguyên thủy có thể hoán đổi cho nhau với các số nguyên. Đó là lý do thực sự tại sao họ không thể được sử dụng như là chìa khóa. Các khóa và giá trị của NSDictionary cần phải là đối tượng. Nhưng vì enums là số nguyên, bạn chỉ có thể quấn chúng thành các đối tượng NSNumber. Đây có lẽ là tùy chọn đơn giản nhất.

Một tùy chọn khác, nếu enums tiếp giáp từ 0 đến một số (tức là bạn không đặt bất kỳ giá trị nào theo cách thủ công), là bạn có thể sử dụng NSArray trong đó chỉ mục thể hiện giá trị của khóa. (Bất kỳ "mất tích" mục sẽ phải được lấp đầy với NSNull.)

28

Với gợi ý VoidPointer, nó có thể tốt hơn để sử dụng NSValue cho những lần khi đếm lần lượt ra không phải là số nguyên (ví dụ như khi -fshort-enums là trong vở kịch, mà không bao giờ như bạn có thể phá vỡ khả năng tương thích với Foundation).

NSValue *value = [NSValue value: &myEnum withObjCType: @encode(enum ETest)]; 

Đó sẽ không để thêm nhiều ở đây nhưng mang đến cho bạn vị tướng "Tôi muốn sử dụng < tên của phi ObjC loại > trong một lớp bộ sưu tập" kỹ thuật.

Lưu ý rằng với trình biên dịch hiện đại, bạn có thể nói enums to use a fixed underlying type. Điều này có nghĩa là bạn có thể kiểm soát dung lượng lưu trữ được sử dụng cho enum, nhưng như giải pháp trên là chung nó vẫn áp dụng ngay cả khi bạn biết điều này.

+0

Tốt, điều này thực sự là một phù hợp hơn vì nó chính xác những gì NSValue là có cho. NSValue có sao chép giá trị được trỏ tới int ctor không? – VoidPointer

+0

Ok, http://cocoadev.com/forums/comments.php?DiscussionID=1169&page=1 nói rằng nó thực hiện một bản sao :) – VoidPointer

+0

Tôi đang làm những gì bạn đề xuất để chuyển đổi UIKeyboardType thành 'NSValue', nhưng tôi đang nhận được một lỗi: http://stackoverflow.com/questions/6130315/how-to-add-a-method-to-uitextfield-uitextview/6132880#6132880 – ma11hew28

9

Tiếp tục mở rộng trên những gợi ý từ Graham Lee ...

Bạn có thể sử dụng một cách khách quan-c category để thêm một phương pháp để NSMutableDictionary cho phép bạn thêm một giá trị với một chìa khóa kiểu NSObject phi bạn . Điều này giữ cho mã của bạn không bị ràng buộc bởi cú pháp gói/unwrapping.

Một lần nữa, giả sử

enum ETest { FOO, BAR }; 

tiên, chúng ta đang thêm một constructor thuyết phục để NSValue:

@interface NSValue (valueWithETest) 
+(NSValue*) valueWithETest:(enum ETest)etest; 
@end 

@implementation NSValue (valueWithETest) 
+(NSValue*) valueWithETest:(enum ETest)etest 
{ 
    return [NSValue value: &etest withObjCType: @encode(enum ETest)]; 
} 
@end 

Tiếp theo chúng ta sẽ thêm hỗ trợ 'enum ETest' để NSMutableDictionary

@interface NSMutableDictionary (objectForETest) 
-(void) setObject:(id)anObject forETest:(enum ETest)key; 
-(id) objectForETest:(enum ETest)key; 
@end 

@implementation NSMutableDictionary (objectForETest) 
-(void) setObject:(id)anObject forETest:(enum ETest)key 
{ 
    [self setObject: anObject forKey:[NSValue valueWithETest:key]]; 
} 
-(id) objectForETest:(enum ETest)key 
{ 
    return [self objectForKey:[NSValue valueWithETest:key]]; 
} 
@end 

Ví dụ ban đầu do đó có thể được chuyển thành

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 
[dict setObject: @"Bar!" forETest:BAR]; 
NSLog(@"getting value Bar -> %@", [dict objectForETest: BAR]);  
[dict release]; 

Tùy thuộc vào mức độ bạn sử dụng enum để truy cập từ điển, điều này có thể làm giảm khả năng đọc mã của bạn một chút.

+0

thời gian để ngừng trả lời ping-pong :-). 1 cho loại NSValue, cá nhân tôi sẽ không sử dụng danh mục NSMutableDictionary mặc dù. Tôi không ngừng tự hỏi tại sao tôi không vượt qua một đối tượng như là chìa khóa. Và tại sao tôi không thể gọi '- [NSDictionary objectForETest:]': -/ –

+0

Tôi ước có ít nhất một cách để xác định "loại" của một số/bất kỳ nguyên thủy, á la '[object class]'. nó sẽ làm cho quá trình boxing/unboxing LOT trở nên dễ sống hơn. –

2

Tôi thích cách tiếp cận danh mục cũng như có thể sẽ thực hiện điều này trong trường hợp của tôi. Với các biểu thức văn học/quyền anh mới bất kể nó được gọi là gì, sẽ sử dụng @ (FOO) để chăm sóc boxing cho bạn như thế nào?

Tôi nghĩ rằng nó sẽ và nếu như vậy hoạt động rất minh bạch bằng cách rõ ràng boxing enum khi sử dụng nó như là một chìa khóa.

Các vấn đề liên quan