2011-08-31 24 views
17

Tôi đã nói với một fellow StackOverflow user rằng tôi không nên sử dụng phương pháp getter khi phát hành một tài sản:Tại sao tôi không nên sử dụng getter để giải phóng tài sản trong mục tiêu-c?

@property(nonatmic, retain) Type* variable; 
@synthesize variable; 

// wrong 
[self.variable release]; 

// right 
[variable release]; 

Ông không giải thích chi tiết lý do tại sao. Chúng cũng giống như tôi. My iOS book cho biết getter trên một bất động sản sẽ trông như thế này:

- (id)variable { 
    return variable; 
} 

Vì vậy, không có nghĩa này [self variable], self.variable, và variable đều như nhau?

+0

Đó là một đề xuất rất nguy hiểm; getter sẽ không luôn luôn như thế. Trong thực tế, nếu đó là một tài sản 'nguyên tử' nó sẽ -cho phép/-autorelease. – bbum

Trả lời

4

Một getter điển hình sẽ trông như thế này:

- (id)variable { 
    return [[variable retain] autorelease]; 
} 

Vì vậy, nếu bạn sử dụng [self.variable release] bạn có thêm một retainautorelease mà bạn không thực sự cần khi bạn chỉ muốn giải phóng đối tượng và nguyên nhân đó đối tượng được giải phóng sau khi cần thiết (khi thoát ra khỏi bể tự động).

Thông thường, bạn sẽ thể sử dụng self.variable = nil trong đó có những lợi ích mà nó cũng đặt biến để nil (tránh tai nạn do con trỏ tòn ten), hoặc [variable release] mà là nhanh nhất và có thể thích hợp hơn trong một phương pháp dealloc nếu setter của bạn có logic tùy chỉnh.

9

Bạn có thể tùy ý viết hành vi của trình xử lý tùy chỉnh, điều này có thể dẫn đến hành vi hoàn toàn khác. Vì vậy, bạn không thể luôn luôn giả định rằng [variable release] có cùng kết quả như [self.variable release].

Đồng thời, bạn có thể viết các thuộc tính tùy chỉnh mà không có một nền trắng độc quyền sao lưu chúng ... nó có thể bị lộn xộn nhanh nếu bạn bắt đầu giải phóng các đối tượng khỏi các tham chiếu được trả về bởi getters!

Có thể có thêm lý do mà tôi không biết gì về ...

+0

Điều này đúng, nhưng tôi không thể hình dung loại trình thu thập nào sẽ thay đổi thuộc tính theo cách người dùng không thể giải phóng nó.) – Eimantas

+1

@Eimantas: Tôi không thể, tuy nhiên, nói rằng bạn đang giải phóng các đối tượng qua getters trong dealloc của bạn ... Mã được viết trong getter tùy chỉnh có thể cố gắng truy cập các ivars khác đã được phát hành, dẫn đến sự cố. Hoặc những trường hợp kỳ lạ khác như thế! – MechEthan

+3

Có thể getter có thể trả lại bản sao tự động? Nó sẽ là một ý tưởng khủng khiếp, nhưng nó vẫn sẽ hợp lệ. Sau đó, trong trường hợp đó, việc giải phóng giá trị trả về bởi getter sẽ làm hỏng chương trình của bạn bằng cách giải phóng một đối tượng. –

13

Đối với tài sản không có accessor tùy chỉnh giữ lại, bạn có thể giải phóng các đối tượng bằng cách:

self.variable = nil; 

này có tác dụng thiết lập ivar (có thể không được gọi là 'biến' nếu bạn chỉ khai báo các thuộc tính) thành nil và giải phóng giá trị trước đó.

Như những người khác đã chỉ ra, hoặc trực tiếp phát hành các ivar (nếu có) hoặc sử dụng phương pháp trên là OK - những gì bạn không phải làm là phát hành cuộc gọi trên biến trở về từ một getter.

+0

Tôi biết tôi đã quên một điều gì đó quan trọng trong câu trả lời của mình ... upvoted của bạn bởi vì nó là một điều quan trọng cần hiểu! – MechEthan

+0

Tôi đọc ở [nhiều nơi] (http://stackoverflow.com/questions/5737312/set-to-nil-in-viewdidunload-but-release-in-dealloc/5737438#5737438) rằng các thuộc tính sẽ được phát hành trong ' dealloc' và đặt thành nil trong 'viewDidUnload'. – JoJo

+1

Nếu bạn cũng có ivar, bạn có thể trực tiếp giải phóng nó. Vấn đề là bạn không thể giải phóng những gì được trả về từ getter vì điều này không được đảm bảo là biến tiềm ẩn thực sự. Trực tiếp phát hành các ivar không ngăn chặn bất kỳ logic tùy chỉnh trong setter đang được thực hiện, nếu bạn không có bất kỳ, nó làm cho ít hoặc không có sự khác biệt. – jrturton

4

không phải tất cả getters lấy mẫu đơn này:

- (id)variable { return variable; } 

... mà chỉ đơn thuần là hình thức nguyên thủy nhất. riêng các thuộc tính nên đề xuất nhiều kết hợp hơn, thay đổi việc thực hiện. trình truy cập nguyên thủy ở trên không tính đến các thành ngữ được sử dụng kết hợp với quản lý bộ nhớ, nguyên tử hoặc sao chép ngữ nghĩa. việc triển khai cũng mong manh trong ghi đè lớp con.

một số ví dụ thực sự ngắn gọn theo sau; mọi thứ rõ ràng trở nên phức tạp hơn trong các chương trình thực sự nơi triển khai trở nên phức tạp hơn nhiều.

1) getter có thể không trả lại biến mẫu.một trong nhiều khả năng:

- (NSObject *)a { return [[a copy] autorelease]; } 

2) setter có thể không giữ lại biến mẫu. một trong những khả năng:

- (void)setA:(NSObject *)arg 
{ 
    ... 
    a = [arg copy]; 
    ... 
} 

3) bạn kết thúc với việc thực hiện quản lý bộ nhớ trong suốt chương trình của bạn, mà làm cho nó khó khăn để duy trì. ngữ nghĩa của lớp (và làm thế nào nó xử lý đếm ref dụ biến) nên được giữ ở lớp, và làm theo ước cho kết quả mong đợi:

- (void)stuff:(NSString *)arg 
{ 
    const bool TheRightWay = false; 
    if (TheRightWay) { 
     NSMutableString * string = [arg mutableCopy]; 
     [string appendString:@"2"]; 
     self.a = string; 
     [string release]; 
     // - or - 
     NSMutableString * string = [[arg mutableCopy] autorelase]; 
     [string appendString:@"2"]; 
     self.a = string; 
    } 
    else { 
     NSMutableString * string = [arg mutableCopy]; 
     [string appendString:@"2"]; 
     self.a = string; 
     [self.a release]; 
    } 
} 

thất bại trong việc làm theo các quy tắc đơn giản làm cho mã của bạn khó có thể duy trì và gỡ lỗi và đau đớn để mở rộng.

vì vậy, ngắn gọn là bạn muốn làm cho chương trình của mình dễ bảo trì. gọi phát hành trực tiếp trên một tài sản đòi hỏi bạn phải biết rất nhiều bối cảnh của các hoạt động bên trong của lớp; đó rõ ràng là xấu và bỏ lỡ những lý tưởng mạnh mẽ của OOD tốt.

nó cũng hy vọng các tác giả/lớp con/khách hàng biết chính xác lớp bị lệch khỏi quy ước như thế nào, thật ngớ ngẩn và mất thời gian khi phát sinh sự cố và bạn phải học lại tất cả các chi tiết bên trong khi có vấn đề.).

đó là một số ví dụ nhỏ về cách phát hành cuộc gọi trên kết quả của thuộc tính giới thiệu sự cố. nhiều vấn đề trong thế giới thực có nhiều khó khăn và khó xác định.

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