2010-10-13 16 views
5

Tôi có sau trong tiêu đề:Làm thế nào để giữ lại setter được triển khai với @synthesize?

@property (nonatomic, retain) UIView *overlay; 

Và trong việc thực hiện:

@synthesize overlay; 

Sau đó:

UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
self.overlay = tempOverlay; 
[tempOverlay release]; 

Không phải là biến tempOverlay trên không cần thiết? Tôi không thể chỉ làm:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

Trả lời

11

Một setter giữ lại tổng hợp trông giống như:

- (void)setValue: (id)newValue 
{ 
    if (value != newValue) 
    { 
     [value release]; 
     value = newValue; 
     [value retain]; 
    } 
} 

Trong trường hợp của bạn, bạn có hai phương pháp hợp lệ:

1) Tạo một temp var, alloc/init (= giữ lại), thiết lập để sở hữu , giải phóng.

IView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
self.overlay = tempOverlay; 
[tempOverlay release]; 

2) Không có temp var, được đặt trực tiếp thành ivar.

overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

UPDATE: Nếu bạn sử dụng phương pháp 2), bạn phải xử lý một cách rõ ràng phần còn lại của quản lý bộ nhớ (không chỉ giữ lại), bằng cách phát hành bất kỳ giá trị trước đó nó có thể có trước nếu cần thiết. Nếu chỉ thực hiện một lần trong init (ví dụ), bạn có thể chỉ cần đặt [overlay release]; trong dealloc.

+0

Nếu thiết lập được giữ lại tổng hợp trông giống như bạn có nó, thì điều gì sẽ xảy ra khi giá trị được đặt đầu tiên? Nếu bạn cố gắng để phát hành giá trị cũ trước, nó sẽ không sụp đổ với BAD ACCESS? Hoặc, tất cả các thuộc tính có được tự động tính số lần giữ đầu tiên là 1 không? – ma11hew28

+0

Nên sử dụng phương pháp 2), có lẽ là lần đầu tiên được thiết lập? Nhưng, nếu bạn đang thiết lập nó sau khi nó đã được thiết lập, thì giá trị cũ sẽ không được giải phóng (trừ khi được thực hiện một cách rõ ràng). Vì vậy, điều đó sẽ gây ra rò rỉ bộ nhớ, đúng không? – ma11hew28

+2

Ban đầu, giá trị là nil và gửi bất kỳ thư nào đến nil (bao gồm cả giữ lại/giải phóng) là một số không trả về số không. – jv42

2

Sử dụng thuộc tính retain xác định rằng retain nên được gọi trên đối tượng mới, và các giá trị trước đó được gửi một release.

Vì vậy, trong khối mã thứ hai của bạn, số lượng giữ lại của đối tượng sẽ trở thành 2, vì bạn không còn phát hành nó nữa và setter đang giữ lại nó. Đây không phải là điều bạn muốn.

-2

Có, bạn có thể trực tiếp gán đối tượng mới được tạo cho đối tượng overlay. Nếu bạn muốn, bạn có thể chứng minh điều đó cho chính mình bằng cách in ra các số giữ của đối tượng

NSLog(@"count: %d", [overlay retainCount]); 
+0

-1 Bạn bỏ lỡ vấn đề. Đối tượng đã được tạo với phân bổ. Do đó, bạn sở hữu nó và phải phát hành nó khi bạn đang thực hiện với nó mà bạn đang đi ngay trong trường hợp này. – JeremyP

+0

Tôi không nghĩ vậy. Xem câu trả lời tôi đã đưa ra. – ma11hew28

1

Nếu bạn gán các đối tượng trực tiếp đến tài sản, bạn vẫn phải phát hành nó:

self.overlay = [[[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)] autorelease]; 
+0

Điều này phải không chính xác. Xem câu trả lời tôi đã đưa ra. – ma11hew28

+0

Rất tiếc, tôi không cuộn sang phải để xem 'autorelease'. Đây là một giải pháp đúng, nhưng tôi muốn giải phóng giá trị tạm thời một cách rõ ràng sau khi đặt 'overlay'. – ma11hew28

1

Như tài sản của bạn được định nghĩa với (giữ lại) bất kỳ trường hợp bạn thiết lập bằng cách sử dụng setter tổng hợp (thông qua cú pháp self.overlay) sẽ tự động được gửi một thông điệp duy trì:

// You're alloc'ing and init'ing an object instance, which returns an 
// instance with a retainCount of 1. 
UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

// The overlay property is defined with (retain), so when you assign the new 
// instance to this property, it'll automatically invoke the synthesized setter, 
// which will send it a retain message. Your instance now has a retain count of 2. 
self.overlay = tempOverlay; 

// Send a release message, dropping the retain count to 1. 
[tempOverlay release]; 

Nếu bạn đã làm:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 

Lớp phủ của bạn sẽ bị giữ lại, có thể dẫn đến rò rỉ tại một số thời điểm trong đơn đăng ký của bạn.

0

Cảm ơn tất cả các câu trả lời.Tôi có một số tuyên bố mâu thuẫn nhau vì vậy tôi đã thử nghiệm sau đây trong một UITableViewController:

- (id)initWithStyle:(UITableViewStyle)style { 
    if ((self = [super initWithStyle:style])) { 
     NSLog(@"count: %d", [overlay retainCount]); 
     self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)]; 
     NSLog(@"count: %d", [overlay retainCount]); 
     [overlay release]; NSLog(@"released once"); 
     NSLog(@"count: %d", [overlay retainCount]);  
     [overlay release]; NSLog(@"released twice"); 
     NSLog(@"count: %d", [overlay retainCount]); 
    } 
    return self; 
} 

tôi đã đầu ra giao diện điều khiển sau:

  • Đôi khi nó chạy tốt:

    count: 0 
    count: 2 
    released once 
    count: 1 
    released twice 
    count: 1 
    
  • Lần khác nó bị lỗi:

    count: 0 
    count: 2 
    released once 
    count: 1 
    released twice 
    Program received signal: “EXC_BAD_ACCESS”. 
    

Tôi biết phương pháp sử dụng tempOverlay là chính xác. Nó chỉ có vẻ rất cồng kềnh, nhưng tôi thích nó để autorelease bởi vì tôi không hiểu làm thế nào autorelease hoạt động hoặc khi nó được gọi. Có một điều chắc chắn là. Mã ở trên là sai vì tôi không muốn overlay để giữ lại số lượng 2.

Điều kỳ lạ là tôi không thể phát hành hai lần. Ngay cả khi nó không sụp đổ, số lượng giữ lại không bị giảm sút.

Dù sao thì, tôi đoán là tôi sẽ sử dụng số tempOverlay ngay bây giờ.

+0

có số lượng giữ lại là 2 là chính xác trong mã bạn có. một lần cho iVar giữ lại, và một lần nữa cho cuộc gọi "phân bổ". – johnbakers

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