2010-10-28 31 views
7

Tôi muốn hiểu cách thiết lập các tham số của thuộc tính (accessors).initializer, thuộc tính, accessors và copy/retain/readonly

Tôi lấy đoạn mã sau từ ví dụ về lịch Kal.

// Holiday.h 

@interface Holiday : NSObject 
{ 
    NSDate *date; 
    NSString *name; 
    NSString *country; 
} 

@property (nonatomic, retain, readonly) NSDate *date; 
@property (nonatomic, retain, readonly) NSString *name; 
@property (nonatomic, retain, readonly) NSString *country; 

- (id)initWithName:(NSString *)name country:(NSString *)country date:(NSDate *)date; 

@end 

// Holiday.m 

#import "Holiday.h" 

@implementation Holiday 

@synthesize date, name, country; 

- (id)initWithName:(NSString *)aName country:(NSString *)aCountry date:(NSDate *)aDate 
{ 
    if ((self = [super init])) { 
    name = [aName copy]; 
    country = [aCountry copy]; 
    date = [aDate retain]; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    [date release]; 
    [name release]; 
    [country release]; 
    [super dealloc]; 
} 

@end 

1) Các thuộc tính được thiết lập để retain, nhưng kể từ khi setter không thể sử dụng các retain làm cho không có ý nghĩa ở đây.

2) Ngoài ra, trong phương thức initWithName, các giá trị được đặt bằng copy. Tại sao không trực tiếp xác định các thuộc tính với copy và sử dụng các phương thức truy cập?

@property (nonatomic, copy) NSString *name; 
// ... 
self.name = aName; 

3) Tôi có cần readonly tại đây không? Tôi không biết tại sao chúng được sử dụng ở đây. Nếu tôi sẽ sử dụng copy cùng với setter các readonly cấm tôi để thiết lập giá trị, bởi vì không có setter.

4) Trong phương pháp initWithName đôi khi copy và đôi khi retain được sử dụng. Tôi sẽ đề nghị sử dụng luôn copy ở đây, vì giá trị không được sửa đổi sau này.

5) Những gì tôi có thể nhớ là nó là OK để copy/retain trong initWithNamerelease trong phương pháp dealloc.

Vậy bạn đề xuất sử dụng retain, copyreadonly trong ví dụ này ở đây như thế nào?

Trả lời

13

ETA: @DougW một cách chính xác chỉ ra rằng hình thức sở hữu của tài sản (assign/retain/copy) không ảnh hưởng đến getter. Nó vẫn ảnh hưởng đến setter. Đối với loại readonly, điều này quan trọng nếu bạn định ghi đè phần readonly của khai báo trong một tiện ích mở rộng lớp, do đó bạn có thể sử dụng trình thiết lập trong quá trình triển khai của mình. Ghi đè thuộc tính tiện ích mở rộng lớp chỉ được phép thay đổi trạng thái readonly của thuộc tính, do đó phần còn lại của nó - có nghĩa là loại nguyên tử và quyền sở hữu - phải được khai báo thích hợp trong tiêu đề. Ngay cả khi bạn không ghi đè thuộc tính ngay bây giờ, bạn có thể trong tương lai, vì vậy bạn cũng có thể ghi lại cách bạn muốn bộ nhớ được quản lý cho chính mình bằng cách sử dụng tùy chọn chính xác để bắt đầu.

Tính tham chiếu tự động (ARC) thay đổi chi tiết triển khai thời gian chạy bằng cách chồng các quy tắc quản lý bộ nhớ của riêng nó lên trên các quy tắc truy cập cổ điển.


Tại sao sử dụng retain với readonly? Nếu bạn đánh dấu một tài sản như retain, các accessor tổng hợp làm một cái gì đó như thế này:

/* getter for retain property */ 
- (NSString *)name { 
    return [[name retain] autorelease]; 
} 

Bây giờ, nếu đối tượng bạn gửi -name để thay đổi tên trong khi bạn vẫn đang sử dụng nó, mã gọi vẫn sẽ có một tham chiếu hợp lệ cho một chuỗi.Nếu bạn tuyên bố nó như assign, tuy nhiên, nó sẽ là như thế này:

/* getter for assign property */ 
- (NSString *)name { 
    return name; 
} 

Bây giờ, càng sớm càng tên được thay đổi bởi các đối tượng, nó sẽ phải được phát hành để tránh rò rỉ, mà sẽ làm mất hiệu lực gọi tham chiếu mã. retain/copy/assign thực sự nêu rõ chính sách quản lý bộ nhớ: retain/copy nói, "Tôi hứa rằng tôi giữ tham chiếu đến bản gốc/bản sao giá trị tôi cung cấp tại đây", trong khi assign nói, "Tôi chỉ có giá trị và yêu cầu không sở hữu tham chiếu đến điều này ".

Khi giá trị không cần quản lý bộ nhớ, chẳng hạn như đồng bằng int, thì assign có ý nghĩa. Khi bạn cố ý không giữ lại một vật thể, chẳng hạn như một đại biểu, thì assign sẽ có ý nghĩa. Tuy nhiên, trong hầu hết các trường hợp khác, bạn sẽ muốn retain hoặc copy.

Hơn nữa, tệp triển khai chỉ có thể ghi đè phần readwrite/readonly của khai báo thuộc tính, không phải phần quản lý bộ nhớ. Như tuyên bố, các tập tin .m có thể có:

setters
@interface Holiday (/*class extension*/) 
@property(nonatomic, retain, readwrite) NSDate *date; 
/* override other properties to make them readwrite... */ 
@end 

ngoài công lập cho các tờ khai tài sản ghi đè sau đó sẽ được tổng hợp cùng với các bộ truy xuất nào.

Tại sao không sử dụng người định cư/người truy cập trong thời gian -init? Bởi vì người định cư/người truy cập thường xuyên thực hiện thông báo KVO, bạn muốn tránh khi đối tượng của bạn không được khởi tạo đầy đủ, tức là trong thời gian -init (khi nó được khởi tạo một nửa trên đường khởi tạo đầy đủ) và -dealloc (khi nó được khởi tạo một nửa) cách hoàn toàn không được khởi tạo).

Tại sao sử dụng copy với readonly? Để trả lời câu hỏi đầu tiên của bạn: bởi vì nếu copy so với retain so với assign sẽ ảnh hưởng đến cả người định cư và getters. Một getter bản sao sẽ trông như thế này:

/* getter for copy property */ 
- (NSString *)name { 
    return [[name copy] autorelease]; 
} 

Tại sao đôi khi copy và đôi khi retain?copy thường được sử dụng với các đối tượng giá trị (đối tượng thụ động đại diện cho một giá trị); retain thường được sử dụng với các đối tượng khác. Đôi khi, các mối quan tâm về hiệu quả hoạt động (rất có thể là sớm ...) và bạn có thể chọn sử dụng retain nơi bạn thường sử dụng copy.

Bạn sử dụng copy/retain cùng với readonly tại đây như thế nào? Khá nhiều như họ đã làm. Tôi muốn ghi đè lên các khai báo trong một phần mở rộng lớp để tôi có thể sử dụng setters để thay đổi các giá trị của thuộc tính bên ngoài của -init-dealloc, nơi tôi sẽ chỉ sử dụng truy cập biến cá thể trực tiếp. Tôi cũng nil ra ivars sau khi phát hành chúng trong -dealloc, ví dụ,

[name release], name = nil; 

Điều này giúp tránh việc gửi tin nhắn đến hoặc tham khảo một đối tượng đã phát hành.

+0

** nonatomic ** giữ lại thuộc tính chỉ trả về con trỏ. Họ ** không ** làm việc lưu giữ, điều tự động. Xem phần ** atomicity ** của tài liệu http://developer.apple.com/library/ios/# documentation/cocoa/Khái niệm/ObjectiveC/Các bài viết/ocProperties.html – JeremyP

+0

@JeremyP: Cuộc gọi tốt. Quyết định không để '[[giữ lại] autorelease]' trong các truy cập không nguyên tử có ý nghĩa: Nếu bạn định giữ giá trị lâu hơn chu kỳ runloop hiện tại, bạn nên tự giữ lại nó. Nếu bạn đang sử dụng 'nonatomic', về cơ bản bạn nói rằng thread-safety không phải là một mối quan tâm. Nếu bạn không phải lo lắng về thread-safety, thì không có mã nào ngoài bạn sẽ thực thi trong khi bạn đang sử dụng giá trị trả về từ accessor, do đó không cần thiết cho accessor thực hiện '[[foo retain] autorelease]' . –

+0

@Jeremy: Tôi sẽ đi xa như vậy để nói rằng bằng cách sử dụng nonatomic có nghĩa là bạn đang nói rằng sự mạnh mẽ không phải là một mối quan tâm - hoặc ít quan tâm hơn hiệu suất. Đặt các thuộc tính thành nonatomic mà không cần phải tính toán số lượng mã của bạn trước tiên như là một tối ưu hóa sớm trong cuốn sách của tôi. – JeremyP

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