2009-04-08 31 views
36

Tôi đang viết một "nhà máy" theo ngữ cảnh sẽ duy trì từ điển của các đối tượng chuyển đổi/hành động kế thừa từ một số lớp Chuyển đổi. Lớp này có một phương pháp:Sử dụng lớp làm khóa trong NSDictionary

- (Class)classResponsibility 

Hoặc một cái gì đó tương tự, như vậy mà một lớp StringConverter sẽ thực hiện các phương pháp như:

- (Class)classResponsibility { 
    return [NSString class]; 
} 

Sau đó để lưu trữ chuyển đổi mà trong từ điển, tôi đã hy vọng vào làm một cái gì đó như:

[converters setValue:stringConverter forKey:[stringConverter classResponsibility]]; 

Nhưng trình biên dịch than phiền rằng loại "Lớp" là loại thông số không hợp lệ cho đối số 2 của phương thức setValue: forKey:. Tôi đã muốn tránh đặt chìa khóa làm tên của lớp ("NSString"), nhưng nếu đó là giải pháp tốt nhất thì tôi sẽ đi với nó.

Trả lời

97

Bạn đang sử dụng setValue:forKey: chỉ mất NSString s làm khóa. bạn nên sử dụng setObject:forKey: để thay thế. Một đối tượng lớp (con trỏ tới các đối tượng lớp có thể được chuyển thành kiểu Class) là một đối tượng Objective-C chính thức (một đối tượng lớp là một thể hiện của lớp meta của nó, và bạn có thể sử dụng tất cả các phương thức NSObject trên một đối tượng lớp; đọc thêm về meta-classes here), để chúng có thể được sử dụng ở bất cứ nơi nào các đối tượng được sử dụng.

Một yêu cầu cho các phím của một cuốn từ điển là họ hỗ trợ sao chép (tức là có phương pháp copyWithZone:. Do đối tượng lớp hỗ trợ phương pháp này? Trong thực tế, nó làm. Các lớp NSObject định nghĩa một phương pháp lớp+copyWithZone:, mà documentation một cách rõ ràng . nói rằng nó "cho phép bạn sử dụng một đối tượng lớp như một chìa khóa để một đối tượng NSDictionary" tôi nghĩ đó là câu trả lời cho câu hỏi của bạn

+0

Giải thích tuyệt vời! –

+23

kể từ XCode 4.5, trước tiên bạn cần truyền nó để không nhận được cảnh báo: [dictionary setObject: object forKey: (id ) someClass]; xem câu trả lời này http://stackoverflow.com/questions/12525324/unable-to-use-class-as-a-key-in-nsdictionary/12525479#12525479 – odyth

+0

Bạn có biết lý do kỹ thuật tại sao các khóa phải tuân thủ 'NSCopying' '? – Drux

4

-setValue:forKey: được ghi lại để tham số NSString làm tham số thứ hai. Bạn sẽ phải sử dụng NSStringFromClass()NSClassFromString() làm bộ điều hợp.

+0

Bạn có quyền về lớp trở thành một đối tượng –

+0

Do không phải là tài liệu cho setValue : forKey: nói rằng khóa chỉ phải là một đối tượng khi sử dụng mã hóa khóa-giá trị? Nếu không, nó không thể là bất kỳ đối tượng thực hiện giao thức NSCopying, như NSDictionary? –

3

Tôi đang tìm kiếm setObject: forKey: phương thức thay vì setValue: forKey :. Chữ ký phương thức cho setObject: forKey: accept (id) là cả hai kiểu tham số và phù hợp hơn nhiều.

+0

@Graham Lee: Các lớp học thực hiện NSCopying. Xem tài liệu về phương thức + copyWithZone: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/doc/uid/20000050-copyWithZone_ – user102008

+0

Rất tiếc, lỗi của tôi. –

1

tôi chỉ có một cây trồng tình huống tương tự với thông báo lỗi tương tự chính xác:.

[tempDictionary setObject:someDictionary forKey:someClass]; 

Tất cả tôi đã làm là thực hiện NSCopying giao thức trong someClass:

- (id)copyWithZone:(NSZone *)zone 
{ 
    id copy = [[[self class] allocWithZone:zone] init]; 
    [copy setId:[self id]]; 
    [copy setTitle:[self title]]; 
    return copy; 
} 

Tôi nghĩ rằng những gì đã xảy ra được rằng một bản sao của someClass đã được thực hiện để được sử dụng như chìa khóa, nhưng vì đối tượng của tôi không biết làm thế nào để sao chép chính nó (xuất phát từ NSObject nó đã không có một copyWithZone trong lớp cha) nó bị balked.

Một điều tôi đã tìm thấy với cách tiếp cận của tôi là nó sử dụng một đối tượng làm khóa. Trừ khi tôi đã có đối tượng được khởi tạo, tôi liên tục gọi số allKeys hoặc chỉ liệt kê theo từ điển.

[Sau khi viết điều này, tôi thấy rằng bạn muốn lưu trữ lớp như khóa. Tôi để lại điều này vì tôi đã tiết kiệm rất nhiều thời gian nếu tôi tìm thấy câu trả lời khi tôi tìm kiếm SO.Tôi không tìm thấy bất cứ điều gì như thế này.]

+0

Tôi chỉ tình cờ gặp vấn đề này ngày hôm nay, nhưng đã có lớp khác này hoạt động hoàn hảo trong nhiều tháng và không hiểu tại sao. Có ai biết lý do không? "Mô hình" là một lớp tùy chỉnh bắt nguồn từ NSObject (không tuân thủ NSCoding) 'static NSMutableDictionary * singletonInstances; @implementation SingletonModel + (void) {khởi \t singletonInstances = [[NSMutableDictionary alloc] initWithCapacity: 10]; } + (void) setSharedModel: (Model *) aModel { \t nếu: { \t \t [singletonInstances setObject: aModel forKey: [aModel lớp]] ([singletonInstances objectForKey [lớp aModel]]!); \t} } ' – nobre

+0

@nobre: ​​các đối tượng lớp có thể được sử dụng làm khóa. xem http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html # // apple_ref/doc/uid/20000050-copyWithZone_ – user102008

+0

Bài đăng này có một cuộc thảo luận tốt về những cạm bẫy của việc triển khai 'NSCopying': http://robnapier.net/blog/implementing-nscopying-439 – penfold

30

Tùy chọn khác của bạn là sử dụng [NSValue valueWithNonretainedObject:yourObjectHere] để tạo khóa từ một thứ khác ngoài chuỗi. Tôi chạy vào một vấn đề tương tự và tôi muốn sử dụng một đối tượng CoreData như là chìa khóa và cái gì khác như giá trị. Phương pháp NSValue này hoạt động hoàn hảo và tôi tin đó là mục đích ban đầu của nó. Để quay trở lại giá trị ban đầu, chỉ cần gọi nonretainedObjectValue

+1

Rất thú vị, cảm ơn cái đó. Tôi đã không may đã đi xuống con đường khác, nhưng trong tương lai tôi sẽ nhớ để cung cấp cho một thử. –

+0

Thay thế rất tuyệt vời hơn là thực hiện copyWithZone trong một triệu lớp cho tôi :) – Will

3

Trong khi đối tượng Lớp tạo khóa hoàn toàn tốt trong NSDictionary, điều đáng nói đến là NSMapTable, được mô hình hóa sau NSDictionary, nhưng linh hoạt hơn. để sử dụng làm khóa và/hoặc giá trị, documented để hỗ trợ các tham chiếu yếu và các con trỏ tùy ý.

+0

Giải pháp iOS6 tuyệt vời! – Meda

+0

Đây sẽ là giải pháp ưa thích mới iOS 6 trở lên. –

+0

Bạn có thể sử dụng yếu cho khóa lớp với NSMapTable không? Bất kỳ khả năng nó sẽ âm thầm chết? – Andy

0

Bạn có thể sử dụng các lớp học như NSDictionary 's phím như thế này:

@{ 
    (id)[MyClass1 class] : @1, 
    (id)[MyClass2 class] : @2, 
    (id)[MyClass3 class] : @3, 
    (id)[MyClass4 class] : @4, 
}; 

Hoặc thậm chí như thế này:

@{ 
    MyClass1.self : @1, 
    MyClass2.self : @2, 
    MyClass3.self : @3, 
    MyClass4.self : @4, 
}; 
Các vấn đề liên quan