64

Tôi có một số câu hỏi về các thuộc tính tổng hợp trong Objective-C. Danh sách đầy đủ sau đây, nhưng câu hỏi cơ bản là: Trình biên dịch đảm bảo rằng các thanh ngang cho các thuộc tính tổng hợp được phát hành đúng cách, mặc dù mã của tôi có thể hoặc không bao gồm các phương thức phát hành trong dealloc?Bản phát hành được xử lý như thế nào đối với các thuộc tính giữ lại @synthesized?

Lưu ý: Tôi quyết định không đăng những câu hỏi này vì chúng liên quan chặt chẽ và vì có một số câu hỏi hiện có mà chạm vào về các sự cố riêng lẻ mà không thực sự quan tâm.

câu hỏi Hơi tương tự:


Setup: Hãy xem xét một lớp học với một tài sản duy nhất:

@interface Person : NSObject 
{ 
    NSString * name; 
} 
@property (nonatomic, retain) name; 
@end 

Câu hỏi # 1: Các trường hợp rất cơ bản:

@implementation Person 
@synthesize name; 
@end 

Với thiết lập này, tôi cho rằng name sẽ tự động phát hành bất cứ khi nào một đối tượng Person được phát hành. Trong tâm trí của tôi, trình biên dịch chỉ cần chèn [name release] vào phương thức dealloc như thể tôi đã tự gõ nó. Đúng không?


Câu hỏi # 2: Nếu tôi chọn để viết phương pháp dealloc của riêng mình cho lớp này, và tôi bỏ qua một cuộc gọi đến [name release], sẽ bị rò rỉ?

@implementation Person 
@synthesize name; 
- (void)dealloc { [super dealloc]; } 
@end 

Câu hỏi # 3: Nếu tôi chọn để viết phương pháp dealloc của riêng mình cho lớp này, và tôi bao gồm một cuộc gọi đến [name release], mà sẽ kết quả trong một đúp phát hành, kể từ @synthesize đã chăm sóc nó cho tôi?

@implementation Person 
@synthesize name; 
- (void)dealloc { [name release]; [super dealloc]; } 
@end 

Câu hỏi # 4: Nếu tôi chọn để viết accessor tài sản của riêng mình cho lớp này, nhưng tôi không viết phương pháp dealloc của riêng tôi, sẽ name được rò rỉ?

@implementation Person 
@dynamic name; 
- (void)setName:(NSString *)newName 
{ 
    [newName retain]; 
    [name release]; 
    name = newName; 
} 
@end 

Câu hỏi # 5: Tôi có một cảm giác (dựa trên kinh nghiệm) mà none các kịch bản trên sẽ gây ra rò rỉ hoặc đúp phát hành, kể từ khi ngôn ngữ đã được thiết kế để tránh chúng. Điều đó, tất nhiên, đặt ra câu hỏi "làm thế nào?". Trình biên dịch có đủ thông minh để theo dõi mọi trường hợp có thể không? Điều gì nếu tôi được làm những điều sau đây (lưu ý rằng đây là một ví dụ lố bịch, chỉ có nghĩa là để minh họa cho quan điểm của tôi):

void Cleanup(id object) { [object release]; } 

@implementation Person 
@synthesize name; 
- (void)dealloc { Cleanup(name); } 
@end 

Would rằng đánh lừa trình biên dịch vào thêm [name release] khác với phương pháp dealloc?

Trả lời

57

Q1:

số @synthesize không thay đổi -dealloc cho bạn. Bạn phải tự mình -release số name.

Q2:

Có nó sẽ bị rò rỉ. Cùng lý do như Q1.

Q3:

Không nó sẽ không kích đúp phát hành. Cùng lý do như Q1.

Q4:

Có nó sẽ bị rò rỉ. Cùng lý do như Q1.

Q5:

Không nó sẽ không kích đúp phát hành. Cùng lý do như Q1.


Bạn có thể kiểm tra điều này cho mình bằng cách ghi đè -retain-release-dealloc để báo cáo những gì đang xảy ra.

#import <Foundation/Foundation.h> 

@interface X : NSObject {} 
@end 
@implementation X 
-(oneway void)release { 
     NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1); 
     [super release]; 
} 
-(id)retain { 
     NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1); 
     return [super retain]; 
} 
-(void)dealloc { 
     NSLog(@"Dealloc %p", self); 
     [super dealloc]; 
} 
@end 

@interface Y : NSObject { 
     X* x; 
} 
@property (nonatomic, retain) X* x; 
@end 
@implementation Y 
@synthesize x; 
- (void)dealloc { [x release]; [super dealloc]; } 
@end 

int main() { 
     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
     Y* y = [[Y alloc] init]; 
     X* x = [[X alloc] init]; 
     y.x = x; 
     [y release]; 
     [x release]; 
     [pool drain];              
     return 0; 
} 

Trong Q1, Q2 và Q4, cuối cùng -retainCount của x là 1, vì vậy không bị rò rỉ, và trong Q3 và Q5 cuối cùng -retainCount là 0 và -dealloc được gọi, vì vậy không có rò rỉ.

+2

Cảm ơn bạn đã trả lời chi tiết. Tôi rất vui vì tôi đã hỏi! –

+0

Rất được giải thích! –

17

Từ Objective-C documentation on properties:

dealloc

thuộc tính khai báo cơ bản mất nơi phương pháp accessor tờ khai; khi bạn tổng hợp một thuộc tính , trình biên dịch chỉ tạo ra bất kỳ phương thức truy cập vắng mặt nào. Có không có tương tác trực tiếp với phương thức deal2oc — các thuộc tính không phải là được tự động phát hành cho bạn. thuộc tính khai báo làm gì, tuy nhiên, cung cấp một cách hữu ích để kiểm tra chéo việc thực hiện các phương pháp dealloc của bạn: bạn có thể tìm kiếm tất cả các tờ khai tài sản trong tập tin tiêu đề của bạn và chắc chắn rằng đối tượng thuộc tính không được đánh dấu assign là được phát hành và những người được chỉ định là không được phát hành.

Điều này chủ yếu trả lời tất cả câu hỏi của bạn.

+0

+1 Cảm ơn bạn đã liên kết. Điều đó chắc chắn là tâm điểm của vấn đề. –

8

Quy tắc đơn giản và chung chung: nếu bạn phân bổ, giữ lại hoặc sao chép đối tượng, BẠN phải phát hành nó.

Khi bạn sử dụng cài đặt ngữ nghĩa setter retain setter trong câu lệnh @synthesize, bạn đang yêu cầu trình biên dịch tạo cho bạn một trình thiết lập gọi số retain trên đối tượng. Không hơn không kém. Và vì bạn đang giữ lại đối tượng đó (mặc dù nó thông qua mã được tạo tự động một cách kỳ diệu), bạn phải giải phóng nó và nơi để giải phóng nó là trong -(void)dealloc.

+4

+1 Đó là một quy tắc tuyệt vời (và không được tham chiếu). Nhiều người (bao gồm cả tôi, khi tôi hỏi câu hỏi này) không nhận ra rằng việc chỉ định "giữ lại" hoặc "sao chép" trong một tờ khai tài sản vẫn đủ tiêu chuẩn. Tôi nghĩ rằng vấn đề nằm trong từ ngữ: "Did * I * giữ lại giá trị? Không, mã automagic của trình biên dịch đã làm nó cho tôi. Rất tiếc." –

+1

Một vài tháng sau khi đăng câu trả lời này, tôi đã đăng một câu trả lời hay hơn, tại đây: http://stackoverflow.com/questions/5122786/iphone-objective-c-should-this-value-be-released/5122821#5122821 Nó có một sự ghi nhớ tốt trong đó. Đi xem. –

+0

các nội dung hay. Tôi hy vọng nó bắt được! –

2

Điều gì đó đáng để biết - nếu bạn có một thuộc tính tổng hợp, hãy đặt thuộc tính đó thành không (bằng cách sử dụng cú pháp dấu chấm, tất nhiên) sẽ giải phóng mã vạch cho bạn.

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