2013-03-31 26 views
8

tôi muốn bảo vệ quyền truy cập vào NSMutableArray trong giao diện công cộngBảo vệ từ việc thêm đối tượng để NSMutableArray trong giao diện công cộng

tôi đang cố gắng để làm điều này bằng cách định nghĩa tài sản như NSArray trong giao diện nào và như NSMutableArray trong giao diện riêng như thế này:

@interface Order : NSObject 
@property (readonly, strong, nonatomic) NSArray* comments; 
@end 

@interface Order() 
@property (readwrite, strong, nonatomic) NSMutableArray* comments; 
@end 

Nhưng điều này không làm việc - vì vậy tôi phải xác định tài sản trong giao diện công cộng NSMutableArray thay vì:

@interface Order 
@property (strong, nonatomic) NSMutableArray* comments; 
@end 

mục đích là để cung cấp quyền truy cập chỉ đọc vào nhận xét cho các ứng dụng API và toàn quyền truy cập vào các phương thức như addObject: trong quá trình triển khai.

mục tiêu Vì vậy, Xác định rõ ràng hơn nhiều:

  1. Khách hàng nên có quyền truy cập đến tài sản như NSArray mà không có khả năng truy cập vào các phương pháp đột biến.
  2. Khách hàng không được có khả năng cập nhật nhận xét để trỏ đến giá trị mới.
  3. Giải pháp phải được thực hiện mà không cần tạo thêm cấu trúc và sao chép mảng.

Vì vậy, chỉ đơn giản là câu hỏi là nếu có thể đưa ra định nghĩa công khai về tài sản tổng quát hơn (NSArray thay vì NSMutableArray).

Có cách nào khác sạch sẽ để đạt được mục tiêu hoặc tôi phải sử dụng NSMutableArray ở khắp mọi nơi?

GIẢI

Sau khi xem xét câu hỏi và câu trả lời tôi nhận ra rằng tôi muốn sử dụng lớp chung chung hơn NSArray trong giao diện công cộng và NSMutableArray trong việc thực hiện ban đầu của tôi - nhưng nó chỉ là không thể cho một tài sản. Vì vậy, câu trả lời là không thể.

Vì vậy, tôi sẽ chỉ sử dụng một thuộc tính duy nhất với NSMutableArray mà không cần thêm bất kỳ sự bảo vệ mong muốn nào.

Nhưng tôi cũng sẽ chọn câu trả lời phù hợp nhất mà nó có thể hữu ích nếu bạn thực sự thích bảo vệ hơn sự đơn giản và hiệu quả.

Trả lời

13

Bạn không cần một công tài sản nếu tất cả các bạn muốn là để cho phép khách hàng để đọc mảng.

Chỉ cần tạo một phương pháp accessor trả về một bản sao của mảng có thể thay đổi cá nhân của bạn:

@interface Order : NSObject 
- (NSArray *)allComments; 
@end 

@implementation Order() 
@property (nonatomic, strong) NSMutableArray * comments; 
@end 

@implementation Order 

@synthesize comments; 

- (NSArray *)allComments 
{ 
    return [[self comments] copy]; 
} 

@end 

mô hình này có thể được nhìn thấy trong ví dụ, NSView: constraintssubviews là nội bộ có thể thay đổi, nhưng chỉ tiếp xúc để đọc thông qua một phương thức duy nhất trả về mảng không thể biến đổi.

+1

Chọn câu trả lời này là phù hợp nhất cho câu hỏi ban đầu. Nhưng tôi sẽ không sử dụng "bản sao" và sẽ không tạo thêm getter - sẽ giữ mã một chút không được bảo vệ, nhưng sạch sẽ * đơn giản với một tài sản. Cảm ơn câu trả lời! – Vladimir

+0

Vladimir, xin chào, tôi chính xác trong tình huống tương tự như bạn. Tại sao bạn không đi với giải pháp này? Nó âm thanh thực sự là một giải pháp tuyệt vời cho vấn đề của chúng tôi; vấn đề với sao chép nông của mảng là gì? – kernix

0

Nếu bạn không muốn khách hàng có thể đặt thuộc tính này, thì hãy khai báo nó trong giao diện công khai là readonly. Nếu bạn không muốn máy khách có thể thay đổi mảng mà máy khách có thể đọc, thì hãy khai báo nó là NSArray. Trong khi đó, bên cạnh bạn là readwritecopy. Bằng cách là readwrite, bạn có thể lấy một số mutableCopy (sẽ là NSMutableArray), thực hiện các thay đổi của bạn và sau đó đặt lại thuộc tính; bằng cách là copy bạn đảm bảo rằng khách hàng luôn nhìn thấy NSArray.

Vì vậy, khách hàng:

NSArray* arr = order.comments; // ok 
[arr addObject: @"ha"]; // no, can't 
order.comments = someOtherArray; // no, can't 

Bên thứ tự:

NSMutableArray* marr = self.comments.mutableCopy; 
[marr addObject: @"ha"]; 
self.comments = marr; // and it is magically turned back into an NSArray 
3

Một giải pháp sẽ là khai báo thuộc tính là chỉ đọc là NSArray. Sau đó, trong quá trình triển khai, hãy tạo thuộc tính riêng, có thể ghi dựa trên NSMutableArray.

Trong .h:

@interface Order : NSObject 
@property (readonly, strong, nonatomic) NSArray* comments; 
@end 

Trong .m:

@interface Order() 
@property (strong, nonatomic) NSMutableArray* internalComments; 
@end 

Thay vì tổng hợp thuộc tính readonly, viết:

- (NSArray *)comments { 
    return [self.internalComments copy]; 
} 

Trong .m bạn làm mọi thứ với self.internalComments.

1

Hai giải pháp:

  1. Return một bản sao không thể thay đổi của mảng - khách hàng được tất cả các ý kiến ​​trong một đi.
  2. Trả lại số lượng nhận xét và nhận xét cá nhân.

Hãy chọn của bạn, có lập luận cho cả hai và nó phụ thuộc vào những gì phù hợp với bạn:

@interface Order : NSObject 

// solution one - return a copy 
@property (readonly, strong, nonatomic) NSArray* comments; 

// solution two - return individual comments 
@property (readonly) NSUInteger commentCount; 
- (id) comment:(NSUInteger)number; 

@end 

@interface Order() 

// internal property - mutable 
@property (readwrite, strong, nonatomic) NSMutableArray* privateComments; 

@end 

@implementation Order 

// solution one - return a copy 
- (NSArray *) comments   { return [self.privateComments copy]; } 

// solution two - return individual comments 
- (NSUInteger) commentCount  { return self.privateComents.count; } 
- (id) comment:(NSUInteger)number { return self.privateComment[number]; } 

@end 
2

Một giải pháp xa sạch hơn, nếu nó có thể chấp nhận đối với trường hợp sử dụng của bạn, sẽ được kê khai tài sản như an NSArray, trong khi sao lưu nó bằng NSMutableArray. Khách hàng về mặt kỹ thuật có thể sửa đổi mảng bằng cách chỉ đơn giản là biến nó thành một mảng có thể thay đổi được, nhưng bạn đang làm rõ rằng làm như vậy sẽ là một ý tưởng tồi.

A @property đơn giản chỉ là trình bao bọc xung quanh hai phương thức, trình lấy và bộ đặt, thường được hỗ trợ bởi biến lưu trữ. Cách đơn giản nhất để thực hiện giải pháp này sẽ là:

@interface Order : NSObject 
{ 
    NSMutableArray *_comments; 
} 

@property (readonly, strong, nonatomic) NSArray *comments; 

- (void)addComment:(Comment *)comment; 

@end 

@implementation Order 
@synthesize comments=_comments; // Can be omitted if you use Xcode 4.4+ 

- (void)addComment:(Comment *)comment 
{ 
    [_comments addObject:comment]; 
} 

@end 

Nếu bạn muốn người dùng có thể thay thế toàn bộ mảng (order.comments = ...), loại bỏ các readonly thuộc tính trên tài sản và ghi đè lên -setComments: phương pháp:

- (void)setComments:(NSArray *)array 
{ 
    [_comments release]; // Can be omitted if you are using ARC 
    _comments = [array mutableCopy]; 
} 

nó đáng chú ý là kể từ khi Objective-C là một ngôn ngữ năng động, nó không thể ngăn chặn hoàn toàn một người nào đó truy cập vào một biến, như bạn có thể interface directly with the runtime hoặc gọi phương pháp bằng cách chọn của họ nếu bạn thực sự muốn poke xung quanh trong những điều bạn không phải. Tất cả những gì bạn thực sự có thể làm là làm cho nó rõ ràng rằng làm như vậy là một ý tưởng tồi.

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