2009-06-03 34 views
7

Sau khi đọc Key-Value Mã hóa Programming Guide, các Key-Value Quan sát Programming Guidemẫu Hướng dẫn đối tượng thực hiện, cũng như đọc nhiều mục StackOverflow về chủ đề này và thử nghiệm với kịch bản mô hình khác nhau, tôi cảm thấy như tôi có một nắm bắt tốt về cách mô hình dữ liệu của tôi.Các mối quan hệ "to-nhiều" có nên được mô hình hóa như là các thuộc tính không?

Tôi kết thúc bằng cách sử dụng thuộc tính được khai báo cho tất cả thuộc tính của tôi và mối quan hệ một-một, được hỗ trợ bởi các dấu hiệu riêng tư. Đối với các thuộc tính chỉ đọc cần phải được ghi riêng tư, tôi sử dụng thuộc tính readonly trong khai báo giao diện .h, sau đó khai báo lại thuộc tính với thuộc tính readwrite trong tiện ích mở rộng lớp được khai báo trong tệp .m. Bên trong các phương thức lớp, tôi luôn sử dụng các trình truy cập thuộc tính với cú pháp dấu chấm và không bao giờ truy cập trực tiếp vào các cá thể riêng tư. Tuy nhiên, có một khía cạnh vẫn khiến tôi bối rối: làm thế nào để mô hình hóa đúng mối quan hệ, đặc biệt khi bộ sưu tập được công khai bất biến, nhưng có thể thay đổi riêng tư (tức là người tiêu dùng của đối tượng mô hình không thể thêm hoặc loại bỏ các đối tượng vào). bộ sưu tập, nhưng nội dung của bộ sưu tập được quản lý riêng bởi lớp).

Tôi hiểu cách triển khai phương thức truy cập KVC cho nhiều mối quan hệ (countOf<Key>, objectsIn<Key>AtIndex, v.v.) và đây là tuyến đường tôi đã theo dõi từ trước tới nay.

Tuy nhiên, tôi đã thấy một số mã mẫu sử dụng các thuộc tính được khai báo để lộ các mối quan hệ, không triển khai các phương thức truy cập KVC, nhưng vẫn có thể quan sát được Khóa-giá trị. Ví dụ:

@interface MyModel : NSObject 
{ 
    // Note that the ivar is a mutable array, 
    // while the property is declared as an immutable array. 
    @private NSMutableArray *transactions_; 
} 

@property (nonatomic, retain, readonly) NSArray transactions; 

@end 

-------------------- 

@implementation MyModel 

@synthesize transactions = transactions_; 

- (void)privateMethodThatManagesTransactions 
{ 
    [[self mutableArrayValueForKey:@"transactions"] addObject:t]; 
} 

@end 

Nếu một đối tượng người tiêu dùng cho biết thêm chính nó như là một quan sát viên của một trường hợp MyModel cho con đường quan trọng "transactions", nó sẽ được thông báo bất cứ khi nào giao dịch được thêm vào hoặc lấy ra từ bộ sưu tập transactions (miễn là các đột biến là được thực hiện thông qua phương pháp mutableArrayValueForKey:).

Với tôi, điều này có vẻ như cách sạch nhất để vạch trần các mối quan hệ với nhiều người vì tôi không cần phải viết mã bộ thu KVC và nó giữ mã sạch.

Tuy nhiên, nó dường như không phải là cách được quảng bá bởi tài liệu của Apple, và tôi không thể không tự hỏi nếu thực tế là nó hoạt động chỉ là một tác dụng phụ không đáng tin cậy. Vì vậy, trước khi cam kết với một kỹ thuật hay cách khác trong các lớp mô hình thực tế của tôi cho một dự án mà tôi bắt đầu làm việc, tôi muốn nhận được ý kiến ​​và lời khuyên của các nhà phát triển Cocoa có kinh nghiệm. Vì vậy, câu hỏi đặt ra là: nếu tôi sử dụng các thuộc tính để mô hình hóa các mối quan hệ với nhiều mối quan hệ, tôi vẫn cần triển khai các phương thức accessor/mutator của KVC chưa? Không.

Cập nhật

Ngay cả khi tôi tuyên bố một tới nhiều tài sản như readonly, như trong ví dụ trên, mã bên ngoài vẫn có thể gọi mutableArrayValueForKey:@"transactions" trên đối tượng mô hình và biến đổi bộ sưu tập. Điều này dường như chỉ ra rằng việc sử dụng các thuộc tính được khai báo cho nhiều mối quan hệ không phải là cách để đi, nhưng tôi vẫn cảm thấy như tôi không hiểu ...

+0

Tôi vừa nhận ra rằng ngay cả đối với các thuộc tính đơn giản đại diện cho thuộc tính hoặc mối quan hệ một, khai báo thuộc tính là chỉ đọc trong .H và khai báo lại nó dưới dạng ghi đè trong .M cho phép mã bên ngoài thay đổi giá trị thuộc tính bằng cách sử dụng KVC setValue: forKey: ... Vì vậy, nó có vẻ như KVC cho phép bỏ qua ngữ nghĩa thể hiện trong tuyên bố tài sản trong mọi trường hợp, vì vậy tôi đoán tôi không nên ngạc nhiên khi có thể biến đổi một bộ sưu tập chỉ đọc bằng cách sử dụng mutableArrayValueForKey: .. –

Trả lời

6

Có.

Tuy nhiên, có một khía cạnh khiến tôi bối rối: cách mô hình hóa đúng mối quan hệ, đặc biệt khi bộ sưu tập được công khai bất biến, nhưng có thể thay đổi riêng tư….

Dễ dàng: Khai báo thuộc tính là readonly trong tiêu đề, sau đó redeclare it as readwrite, copy in a class extension trong tệp triển khai.

Tôi hiểu làm thế nào để thực hiện các phương pháp accessor KVC cho đến nhiều mối quan hệ (countOf<Key>, objectsIn<Key>AtIndex, vv) và đây là con đường tôi đã theo dõi cho đến nay.

Cũng có những thay đổi đột biến. Với những thứ này, bạn không cần sử dụng mutableArrayValueForKey:; thay vào đó, bạn có thể sử dụng trực tiếp các trình truy cập đột biến. Bạn vẫn sẽ nhận được thông báo KVO, bởi vì KVO kết thúc tốt đẹp những phương pháp đó lần đầu tiên một cái gì đó tự thêm vào như một người quan sát cho tài sản.

Tôi có a list of the accessor selector formats, bao gồm cả những người truy cập đột biến, trên blog của tôi.

Edit:

Ngay cả khi tôi tuyên bố một tới nhiều tài sản như readonly, như trong ví dụ trên, mã bên ngoài vẫn có thể gọi mutableArrayValueForKey:@"transactions" trên đối tượng mô hình và biến đổi bộ sưu tập.

Đây là lý do chính đáng để làm cho thói quen sử dụng trình truy cập đột biến và tránh mutableArrayValueForKey:. Bạn sẽ không gửi tin nhắn đột biến từ bên ngoài lớp nếu bạn nhận được một cảnh báo trình biên dịch (không có phương thức [public] như vậy) bất cứ lúc nào bạn thử nó.

Mặc dù tính khả dụng của mutableArrayValueForKey: và rủi ro mà ai đó sẽ sử dụng nó, thuộc tính tuân thủ KVO cách để truy cập tại đây.

+0

Cảm ơn câu trả lời nhanh. Tôi đã chỉnh sửa câu hỏi của mình để làm cho nó chính xác hơn: nếu tôi sử dụng các thuộc tính để mô hình hóa nhiều mối quan hệ, tôi vẫn cần phải triển khai các phương thức accessor/mutator của KVC? –

+0

Có. Bạn có thể tổng hợp getter, nhưng setter sẽ sai nếu bạn muốn một đối tượng có thể thay đổi trong ivar của bạn (@property (copy) cung cấp cho bạn * bản sao không thay đổi) và @synthesize sẽ không cung cấp cho bạn bất kỳ người truy cập chính xác nào (như objectIn AtIndex :). Vì vậy, bạn vẫn cần phải thực hiện * ít nhất là * setter mình. –

+0

Tôi vẫn còn bối rối ... Nếu tôi cần phải thực hiện các phương pháp KVC (accessors và mutators), thì giá trị gia tăng của việc khai báo một thuộc tính trên đầu trang của chúng là gì? –

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