2009-07-13 28 views
5

Tôi đang dần tự dạy ca cao cho iPhone (thông qua Stanford Class on iTunes U) và tôi đã trải qua một phần về quản lý bộ nhớ, và tôi hy vọng sẽ nhận được một số xác nhận rằng các giả định Tôi đang làm cách xử lý bộ nhớ và cách [release] và [autorelease] hoạt động. Vì quản lý bộ nhớ là một phần thực sự cơ bản và cơ bản nhưng rất cần thiết của trải nghiệm lập trình, tôi muốn đảm bảo rằng tôi đang làm đúng.phát hành/autorelease nhầm lẫn trong ca cao cho iphone

Tôi hiểu rằng bất kỳ điều gì có phân bổ, mới hoặc bản sao cần phải được phát hành.
Nếu tôi làm điều này:

NSString *temp = [[NSString alloc] initWithString:@"Hello World"]; 

Sau đó, tôi cần phải thêm [tạm thời phát hành/autorelease] cuối cùng, vì tôi có một alloc.

Tuy nhiên, nếu tôi làm điều này:

NSString *temp = @"Hello World"; 

Sau đó, nó dường như không cần một tuyên bố phát hành. Lớp NSString có tự động gọi tự động là một phần của bài tập không?

Ngoài ra, có sự khác biệt nào giữa hai đối tượng * tạm thời ở đây sau các câu lệnh này không? Cả hai đều chứa cùng một chuỗi, nhưng có cách sử dụng bộ nhớ/cách sử dụng chúng khác nhau không?

Thứ hai, với các thuộc tính, tôi giả sử rằng tự động xử lý tự động được xử lý. Nếu tôi có điều này:

@interface Person : NSObject 
{ 
    //ivars 
    NSString *firstName; 
    NSString *lastName; 
} 

//properties 
@property NSString *firstName; 
@property NSString *lastName; 

///next file 

@implementation Person 

@synthesize firstName; 
@synthesize lastName; 

- (void) dealloc 
{ 

    //HERE!!!! 

    [super dealloc]; 
} 

tôi giả sử tôi không cần phải thêm [firstName phát hành] và [lastName phát hành] (tại // ĐÂY !!!!), vì đó là tự động xử lý bởi các thuộc tính . Đúng không?

Tôi hiểu rằng nếu tôi làm điều này trong mã (giả sử tôi đã xác định initWithFirstName):

Person *Me = [[Person alloc] initWithFirstName: @"Drew", lastName:"McGhie"]; 

mà sau này tôi sẽ phải sử dụng [Me phát hành/autorelease];

Bất kỳ trợ giúp nào xác nhận hoặc chỉnh sửa sự hiểu biết của tôi cho đến nay đều được đánh giá cao.

POST ĐÁP VIẾT-UP

tôi nghĩ rằng tôi muốn viết những dòng này tất cả lên sau khi đi qua tất cả các câu trả lời và kiểm tra ra những gợi ý và nói về những gì đã làm việc.

Tôi cần thêm [firstName release], [lastName release], nhưng tôi cũng cần thêm (giữ lại) vào mô tả thuộc tính. Không thêm cảnh báo (giữ lại) gây ra bởi vì nó giả định (gán). Đây là cách cuối cùng tôi thiết lập lớp học

@interface Person : NSObject 
    { 
     //ivars 
     NSString *firstName; 
     NSString *lastName; 
    } 

    //properties 
    @property (retain) NSString *firstName; 
    @property (retain) NSString *lastName; 

    ///next file 

    @implementation Person 

    @synthesize firstName; 
    @synthesize lastName; 

    - (void) dealloc 
    { 
     [firstName release]; 
     [lastName release]; 
     [super dealloc]; 
    } 

Trả lời

10

Quy tắc rất đơn giản: nếu bạn alloc, copy hoặc retain, trách nhiệm của bạn là release. Nếu không, thì không. Tuy nhiên, nếu bạn cần phải dựa vào một đối tượng ở xung quanh, bạn phải retain (và sau đó là release).

Chúng tôi có thể xử lý chuỗi theo đúng các quy tắc - bạn không cần phải release vì bạn không sở hữu nó. Đó là đơn giản; không cần phải lo lắng về việc liệu họ có phải là trường hợp đặc biệt hay không, chỉ cần làm theo các quy tắc và bạn sẽ ổn thôi.

Tôi đã viết một bài đăng trên blog có bộ sưu tập là articles about the Cocoa memory management rules; Tôi khuyên bạn nên theo dõi một số tài liệu tham khảo.

1

Phần cuối cùng trước tiên: Bạn thực sự phải tự động/giải phóng Me. Tuy nhiên, bạn cũng sẽ phải thêm [firstName release];[lastName release]; trong -dealloc; hoặc tốt hơn; self.firstName = nil;

Đối với chuỗi ký tự; phần này có một chút lông, nhưng [@"String literal" release] về bản chất là một noop.Như vậy, có sự khác biệt giữa hai đối tượng tạm thời, nhưng vì bạn thường sẽ không biết bạn sẽ xử lý đối tượng nào, thêm [temp release]; nói chung là sự lựa chọn an toàn, trừ khi bạn biết nó sẽ chứa một đối tượng autoreleased.

+0

Tôi không phân bổ/sao chép/giữ lại firstName hoặc lastName một cách rõ ràng. Có cần thiết vì phân bổ được phỏng đoán bằng cách tạo tự động tổng hợp mà tôi không thấy trong mã? –

+0

Theo nghĩa nào đó. Vấn đề ở bàn tay là đối tượng của bạn "sở hữu" 'firstName' và' lastName', vì vậy khi chúng được thiết lập, bạn sẽ có trách nhiệm giải phóng chúng. –

3
  1. Tôi chưa bao giờ giải phóng các chuỗi ký tự như NSString *foo = @"x";. Một cách hợp lý, nếu bạn đã phải release kết quả của điều đó, bạn sẽ phải tham số release tham số là initWithString và cả hai tham số là initWithFirstName:lastName:.
  2. Bạn phải làm release hoặc autoreleasefirstNamelastName. Tôi đã nhìn thấy cảnh báo về việc không sử dụng cú pháp thuộc tính trong các destructors, mà tôi nghĩ là cùng một lý do bạn không sử dụng các hàm ảo trong các hàm tạo và các hàm hủy C++.

Giả định của bạn sai. Bạn phải làm một trong hai điều này:

Person *Me = [[Person alloc] initWithFirstName: @"Drew" 
              lastName: @"McGhie"]; 
    ... 
    [Me release]; 

hay này:

Person *Me = [Person personWithFirstName: @"Drew" 
            lastName: @"McGhie"]; 

... và chắc chắn rằng đối tượng Person của bạn xử lý +personWithFirstName:lastName: chính xác, ví dụ: [[[self alloc] initWithFirstName: firstName lastName: lastName] autorelease].

Có thể bạn nên thực hiện mã có mã ít hơn. Rõ ràng là quan trọng, NSAutoreleasePool có thể sẽ không bao giờ là nút cổ chai của bạn, và nếu nó bao giờ là nó dễ dàng cố định.

Tôi nghĩ mọi người đặt rất nhiều nỗ lực vào việc tránh các thông điệp của lớp trả lại đối tượng là một đối tượng không được đánh giá cao. Đó là tối ưu hóa sớm, trong đó nó có lẽ là không cần thiết và thậm chí có thể không phải là điều đúng để làm. Và nó khó khăn hơn để duy trì, bạn sẽ rất có khả năng được theo đuổi rò rỉ mãi mãi.

Ngoài ra, bạn sẽ autorelease một đối tượng bạn phải init (ví dụ: alloc + initPersonWithFirstName:lastName: thay vì sử dụng một thông điệp lớp như personWithFirstName:lastName:), tôi muốn đề nghị bạn làm điều đó ngay lập tức. Nếu không, bạn đang có khả năng theo đuổi cùng một loại rò rỉ. Vì vậy, nếu bạn sẽ không để thêm một phương pháp personWithFirstName:lastName:-Person, làm điều này thay vì:

Person *Me = [[[Person alloc] initWithFirstName: @"Drew" 
              lastName: @"McGhie"] autorelease]; 

Tóm tắt: Cocoa hiện rất nhiều để giúp bạn quản lý bộ nhớ. Hãy chắc chắn rằng bạn không chống lại nó.

Cập nhật dựa trên phản hồi của Jon trong nhận xét.

+0

Thay vì [[[Người cấp phát] initWithFirstName: firstName lastName: lastName] autorelease], [[[self alloc] initWithFirstName: firstName lastName: lastName] autorelease] sẽ phù hợp hơn. Bằng cách sử dụng self, bạn sẽ phân bổ đúng loại đối tượng là có một lớp con người. Ví dụ: [SpecialPerson personWithFirstName: @ "Drew" lastName: @ "McGhie"] sẽ khởi tạo chính xác một người đặc biệt. Trong phương thức "+", tự đề cập đến lớp sở hữu phương pháp. –

+0

Đó là một mẹo * tuyệt vời *, Jon. Sẽ kiểm tra và cập nhật câu trả lời. Cảm ơn! –

1

Giới thiệu firstName/lastName.

Bạn nên luôn luôn, để rõ ràng, hãy nhớ chỉ định thuộc tính của thuộc tính. Thuộc tính mặc định setter là gán, trong trường hợp này bạn muốn sử dụng giữ lại.

@interface Person : NSObject 
{ 
    NSString *firstName; 
} 
@property (retain) NSString *firstName; 
@end 

Với giữ mỗi và chỉ khi bạn sử dụng các ký hiệu dấu chấm để gán một giá trị trình biên dịch chèn một giữ lại: chỉ cần nhớ để luôn sử dụng nó. Đối với tính nhất quán tôi lời khuyên bạn viết initializer bạn theo cách này:

- (id) initWithFirstName:(NSString*) aString 
{ 
    self.firstName = aString; 
} 

và phương pháp dealloc theo cách này:

- (void) dealloc 
{ 
    self.firstName = nil; 
} 

Về @ "" - loại đối tượng. Chúng là các đối tượng NSStrings không đổi. Chỉ cần sử dụng chúng như là các đối tượng NSString (chúng là) và không bao giờ giải phóng chúng. Trình biên dịch sẽ chăm sóc chúng.

+0

Bạn không nên viết init/dealloc theo cách này. Cách tiếp cận này sẽ gửi một thông điệp đến đối tượng, có thể được xử lý bởi một lớp con thay vì thực sự đến lớp của bạn. –

+0

Tôi nghe nói về Apple đề xuất chống lại getter/setters trong init/dealloc, nhưng tôi không thể tìm thấy tài liệu về nó. Bạn có thể đăng đường link đó không? – IlDan

1

Lớp NSString có tự động gọi tự động là một phần của bài tập không?

Lớp NSString không làm bất kỳ điều gì vì bạn không gửi thư. Tất cả những gì bạn đã làm được gán cho một biến. NSString không tìm hiểu về điều này, và nó không phải là kinh doanh của nó.

Ngoài ra, có sự khác biệt nào giữa hai đối tượng * tạm thời ở đây sau các câu lệnh này không? Cả hai đều chứa cùng một chuỗi, nhưng có cách sử dụng bộ nhớ/cách sử dụng chúng khác nhau không?

Cả hai đều là NSStrings, cả hai đều chứa cùng một giá trị và cả hai đều được coi là không thay đổi. Đó là tất cả những gì bạn nên quan tâm.

Thứ hai, với các thuộc tính, tôi giả sử rằng tự động xử lý tự động được xử lý. Nếu tôi có điều này:

@property NSString *firstName; 
@property NSString *lastName; 

- (void) dealloc 
{ 
    //HERE!!!! 

    [super dealloc]; 
} 

tôi giả sử tôi không cần thêm [firstName release][lastName release] (tại //HERE!!!!), vì đó là tự động xử lý bởi các thuộc tính. Đúng không?

No. NSObject sẽ không giải phóng tất cả các giá trị thuộc tính cho bạn; bạn vẫn cần phải giải phóng chúng ở đó.

Ngoài ra, đừng làm self.firstName = nilself.lastName = nil trong dealloc. Những người dịch thành tin nhắn (với phương pháp truy cập của bạn), và khi bạn làm điều đó trong dealloc, bạn đang gửi tin nhắn đến một đối tượng ked half-dealloc. Đó là yêu cầu cho sự cố. Điều tương tự cũng áp dụng cách khác để khởi tạo các giá trị thuộc tính trong init: Sử dụng thuộc tính/người truy cập của bạn sẽ gửi tin nhắn đến một đối tượng được chỉnh sửa một nửa init.

2

NSStrings được tạo với cú pháp @"String here" là các chuỗi không đổi. Đây là những khác nhau từ các chuỗi bình thường.Giống như các chuỗi liên tục C bình thường, chúng được tạo ra khi chương trình của bạn tải và tồn tại trong toàn bộ vòng đời của nó. Lớp NXConstantString, mà chúng thuộc về, bỏ qua tất cả các thông điệp quản lý bộ nhớ. Bạn có thể retainrelease tất cả những gì bạn thích và nó sẽ không tạo ra bất kỳ sự khác biệt nào.

Đối với chuỗi được tạo bằng phương pháp [[NSString alloc] initWith...]-kiểu, áp dụng bình thường memory management rules. Tôi khuyên bạn nên đọc các tài liệu liên kết - chúng không phức tạp, và sau khi đọc chúng, bạn sẽ biết khá nhiều thứ bạn cần biết về quản lý bộ nhớ Cocoa.