18

Trong mô hình của tôi, tôi có một mảng các đối tượng được gọi là sự kiện. Tôi muốn bộ điều khiển của mình được thông báo bất cứ khi nào một đối tượng mới được thêm vào các sự kiện.Quan sát các thay đổi đối với mảng có thể thay đổi bằng KVO và NSNotificationCenter

Tôi nghĩ rằng một cách tốt để làm điều này sẽ sử dụng mô hình KVO để nhận được thông báo khi các sự kiện thay đổi (từ một đối tượng mới được bổ sung)

// AppDelegate 
// events is a NSMutableArray @property/@synthesize etc... 

[appDelagate addObserver:self 
       forKeyPath:@"events" 
        options:NSKeyValueObservingOptionNew 
        context:NULL]; 

Nhưng phương pháp observeValueForKeyPath không được gọi và tôi phát hiện ra rằng Mảng không KVO compliant :-(

Một lựa chọn là tự kích hoạt phương pháp này bằng cách gọi willChangeValueForKey cho keyPath

// ViewController 
[self willChangeValueForKey:@"events"]; 
[self.events addObject:event]; 
[self didChangeValueForKey:@"events"]; 

Nhưng điều này cảm thấy nặng vì tôi có lẽ cũng nên theo dõi trạng thái trước và sau của mảng sự kiện để có thể truy cập từ phương thức observValueForKeyPath.

Một cách tiếp cận có thể là sử dụng mảng tiêu chuẩn (thay vì có thể thay đổi) và tạo/đặt phiên bản sự kiện mới mỗi khi tôi muốn thêm đối tượng mới hoặc tôi có thể tạo thuộc tính riêng các mục nằm trong mảng có thể thay đổi (tôi ước bạn có thể quan sát @ "events.count").

Một tùy chọn khác là sử dụng NSNotificationCenter. Tôi cũng đã đọc một số câu trả lời gợi ý sử dụng các khối (nhưng tôi không biết bắt đầu từ đâu).

Cuối cùng, tôi có thể giữ một phiên bản của bộ điều khiển trong đại biểu của mình và chỉ gửi một thông báo liên quan không?

// Delegate 
[myController eventsDidChange]; 

Có lẻ để giữ tham chiếu đến bộ điều khiển từ đại biểu không?

Tôi đang đấu tranh để hiểu cách chọn phương pháp tốt nhất để sử dụng, vì vậy mọi lời khuyên về hiệu suất, tính linh hoạt mã trong tương lai và các phương pháp hay nhất được đánh giá cao!

Trả lời

18

Bạn không nên tạo các thuộc tính công khai trực tiếp cho các bộ sưu tập có thể thay đổi để tránh biến đổi mà bạn không biết. NSArray không phải là khóa-giá trị quan sát được, nhưng thuộc tính một-nhiều của bạn@"events" là. Dưới đây là làm thế nào để quan sát nó:

Thứ nhất, khai báo một tài sản công cộng cho một bộ sưu tập bất biến:

@interface Model 
@property (nonatomic, copy) NSArray *events; 
@end 

Sau đó, trong việc thực hiện của bạn trở lại nó với một Ivar có thể thay đổi:

@interface Model() 
{ 
    NSMutableArray *_events; 
} 
@end 

và ghi đè lên các getter và setter:

@implementation Model 

@synthesize events = _events; 

- (NSArray *)events 
{ 
    return [_events copy]; 
} 

- (void)setEvents:(NSArray *)events 
{ 
    if ([_events isEqualToArray:events] == NO) 
    { 
     _events = [events mutableCopy]; 
    } 
} 

@end 

Nếu các đối tượng khác cần thêm sự kiện vào mô hình của bạn, thứ ey có thể lấy đối tượng proxy có thể thay đổi bằng cách gọi -[Model mutableArrayValueForKey:@"events"].

NSMutableArray *events = [modelInstance mutableArrayValueForKey:@"events"]; 
[events addObject:newEvent]; 

Điều này sẽ kích hoạt thông báo KVO bằng cách đặt thuộc tính với bộ sưu tập mới mỗi lần.Để có hiệu suất tốt hơn và kiểm soát chi tiết hơn, hãy thực hiện phần còn lại của array accessors.

Xem thêm: Observing an NSMutableArray for insertion/removal.

+2

Cảm ơn bạn! mutableArrayValueForKey thực hiện thủ thuật. Bạn có bất kỳ mẹo nào về cách bạn chọn mẫu để sử dụng (KVO, NotificationCenter, đại biểu) khi bạn muốn liên lạc giữa mô hình với bộ điều khiển không? – MathewS

+0

Tôi chắc chắn thiếu cái gì đó ở đây. Ai đó có thể vui lòng giải thích nơi setEvents sẽ nhận được gọi là nếu ai đó đã thêm hoặc insertObject: atIndex: một đối tượng để các mảng có thể thay đổi sao lưu? –

0

mỗi sự docs on accessor methods, bạn nên thực hiện:

- (void)addEventsObject:(Event*)e 
{ 
    [_events addObject:e]; 
} 

- (void)removeEventsObject:(Event*)e 
{ 
    [_events removeObject:e]; 
} 

Sau đó KVO sẽ cháy thông báo khi chúng được gọi là.

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