2012-03-08 28 views
5

Tôi đang cố gắng quan sát các thay đổi trong từ điển bằng KVO.NSMutableDictionary KVO

Ví dụ:

dictionary = [NSMutableDictionary new]; 
[dictionary setObject:@"test1" forKey:@"key1"]; 
[dictionary setObject:@"test2" forKey:@"key2"];  
[dictionary setObject:@"test3" forKey:@"key1"]; 

Tôi rất muốn có thể treo một quan sát viên cho bất cứ khi nào một giá trị được bổ sung vào từ điển. gỡ bỏ, hoặc thay thế (ví dụ trong trường hợp trên, bất cứ khi nào bất kỳ phương pháp setObject được gọi là)

Vì vậy, trong kết luận: Tôi muốn có một chức năng để có

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 

gọi khi tôi thêm một bất kỳ mục mới vào từ điển, hoặc Xóa bất kỳ mục nhập nào, hoặc THAY THẾ bất kỳ mục nhập nào.

KHÔNG: Tôi KHÔNG muốn chỉ định khóa nào tôi đang quan sát. (ví dụ: chỉ quan sát khi @ "key1" được thêm vào) vì giải pháp này không mở rộng.

+0

Điều gì sẽ xảy ra nếu bạn quan sát khóa '@" @ count "'trên từ điển? –

+0

No. Không hoạt động. Nếu tôi thay thế @ "@ count" bằng @ "key2" thì nó hoạt động nhưng đó không phải là giải pháp chung. –

Trả lời

0

Bạn không thể phân lớp NSMutableDictionary và ghi đè các trình cài đặt khác nhau? Ví dụ: ghi đè setObject: forKey: bằng cách gọi super, sau đó gọi ngay addObserver ...

Bạn cũng có thể viết trình bao bọc cho NSMutableDictionary, nơi bạn buộc mình sử dụng trình tùy chỉnh để thao tác NSMutableDictionary cơ bản.

Có lẽ tôi cần thêm ngữ cảnh cho bất kỳ giới hạn hoặc khả năng mở rộng nào của bạn.

+0

Đó là bất hợp pháp để ghi đè lên NSMutableDictionary (nhiều đến ngạc nhiên của tôi). Gọi [super SetObject: forKey:] gây ra một ngoại lệ nói điều gì đó về một lớp trừu tượng. Tôi đang nghiêng về phía bố cục và thực hiện lại tất cả các chức năng mà từ điển có thể cung cấp (PITA và không có đa hình). Vấn đề khả năng mở rộng được đề cập đến thực tế là bạn chỉ có thể quan sát các thay đổi đối với "key1" trong từ điển và không thay đổi "*" đối với từ điển. Vì vậy, tôi không thể thông báo cho người quan sát nếu một khóa mới được thêm vào từ điển. –

+0

Thú vị thực sự. Cho đến nay tôi nghĩ rằng lớp trang trí có thể là lựa chọn tốt nhất. Bạn không cần phải thực hiện lại tất cả các phương thức. Bạn chỉ có thể có từ điển với tư cách là một thành viên và gọi [myObject.dictionary nsdictionarymethod] cho bất kỳ hoạt động nào không phải của kvo Và chỉ cần triển khai lại các phương thức thêm, thiết lập, loại bỏ. – Vinnie

7

Phân lớp NSMutableDictionary là một chút khó chịu, do thực tế là NSDictionary và bạn bè của nó là các nhóm lớp. Nó chắc chắn có thể thực hiện được, và nếu bạn phải truyền đối tượng đó đến một nhóm các lớp khác, thì bạn có thể muốn làm chính xác điều đó. Nếu không, có thể dễ dàng hơn khi tạo một lớp tổng hợp có cùng API cơ bản và sử dụng đối tượng NSMutableDictionary bên trong để lưu trữ. Có một bài viết khá hay là CocoaWithLove.com, Ordered Dictionary Subclassing, điều này sẽ làm việc này.

Tuy nhiên, điều đó không giải quyết được hoàn toàn vấn đề của bạn. Những gì tôi sẽ đề nghị là bạn bắt đầu với một lớp con hoặc lớp trang trí như lớp trên, sau đó thêm hỗ trợ một cách rõ ràng cho -(NSArray*)allKeys, là một accessor tiêu chuẩn trong chính nó là NSDictionary. Sau đó, bạn có thể thêm hỗ trợ để chuyển đổi cùng với thông điệp thay đổi cho allKeys, điều này sẽ làm cho nó có thể quan sát được.

Điều này có thể được thực hiện bằng cách thêm mã sau đây xung quanh các phương pháp -setObject:forKey:-removeObjectForKey:.

- (void)setObject:(id)anObject forKey:(id)aKey 
{ 
    BOOL addKey=NO; 
    if (![dictionary objectForKey: aKey]) { 
     addKey=YES; 
     [self willChangeValueForKey: @"allKeys"]; 
    } 
    [dictionary setObject:anObject forKey:aKey]; 
    if (addKey) 
     [self didChangeValueForKey: @"allKeys"]; 
} 

- (void)removeObjectForKey:(id)aKey 
{ 
    [self willChangeValueForKey: @"allKeys"]; 
    [dictionary removeObjectForKey:aKey]; 
    [self didChangeValueForKey: @"allKeys"]; 
} 

Điều đang được thực hiện ở đây là chúng tôi thêm thông báo KVO rõ ràng vào lớp khi phím của từ điển được thay đổi để đánh dấu thay đổi trong mảng.

Điều này sẽ đảm bảo thêm và xóa. Nếu bạn muốn thay đổi để được thông báo trên cơ sở tương tự, bạn có thể loại bỏ các câu lệnh if, và chỉ có allKeys thông báo trên một trong hai thiết lập hoặc loại bỏ, như thế này:

- (void)setObject:(id)anObject forKey:(id)aKey 
{ 
    [self willChangeValueForKey: @"allKeys"]; 
    [dictionary setObject:anObject forKey:aKey]; 
    [self didChangeValueForKey: @"allKeys"]; 
} 

Sau đó, trong mã của bạn, bạn đặt trong một người quan sát duy nhất cho khóa @ "allKeys" trên đối tượng này và bạn sẽ nhận được thông báo mỗi khi một mục thay đổi.

+0

Tôi đồng ý với kết luận này. Cảm ơn gaige. Tôi sẽ thực hiện điều này. –

+0

Nếu nó hoạt động, đừng quên bỏ phiếu cho câu trả lời mà bạn thấy hữu ích và đánh dấu là câu trả lời đã cung cấp giải pháp của bạn. – gaige

+0

Khi NSMutableDictionary phát triển về kích thước, các phương thức đó sẽ không được gọi lại cho mỗi khóa? –

0

Tôi hy vọng điều này sẽ rất hữu ích

- (void)addObserver:(id)observer { 
    for (id key in grid) 
     [self addObserver:observer 
       forKeyPath:[key description] 
        options:0 
        context:key]; 
} 
0

Tôi nghĩ một cách khác để làm điều này là sử dụng ghi đè dưới đây, trong trường hợp bạn đang quan sát NSMutableDictionary "allRecentCurrencyData" có giá trị phụ thuộc vào recentBrazilReals, recentEuEuro, recentUkPounds, recentJapanYen , người quan sát sẽ được gọi, nhưng nhược điểm là bạn cần phải biết các phím trước khi bàn tay để làm điều này.

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key 
{ 
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key]; 

    if ([key isEqualToString:@"allRecentCurrencyData"]) { 
     NSArray *affectingKeys = @[@"recentBrazilReals", @"recentEuEuro",@"recentUkPounds",@"recentJapanYen"]; 
     keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys]; 
    } 
    return keyPaths; 
} 
1

tôi giải quyết một vấn đề tương tự bằng cách thêm một người quan sát vào từ điển có thể thay đổi "dịch" theo cách này:

[self addObserver:self forKeyPath:@"[email protected]" options:0 context:NULL]; 

Ứng dụng của tôi quản lý dữ liệu trong một cách cổ điển, sử dụng một tableview, một bộ điều khiển và từ điển như thuộc tính KVO "phiên dịch". Từ điển được ràng buộc với một NSDictionaryController trong XIB của tôi, và một nội dung tableview là ràng buộc với bộ điều khiển.

Đây là những kết nối của tableview:

enter image description here

Bây giờ, trong bất kỳ trường hợp sau đây tôi bắt sự thay đổi:

  • thêm một cặp khóa-giá trị
  • loại bỏ cặp khóa-giá trị
  • thay đổi khóa
  • changi ng giá trị

Lưu ý: không may, cách tiếp cận này không hoạt động với NSMutableArrays. Các thay đổi không được công nhận

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