2009-09-07 30 views
12

Tôi đang tìm cách làm rõ thêm sau khi xem What is responsible for releasing NSWindowController objects?Ai sở hữu một NSWindowController, trong thực hành tiêu chuẩn?

Tôi đang viết một ứng dụng quản lý khoảng không quảng cáo đơn giản cho cháu trai của tôi. Tôi có một cái nhìn bảng hiển thị nội dung của "thư viện" của họ, vv Để thêm một mục mới vào thư viện, họ nhấp vào nút '+'. Nút này sẽ mở ra một cửa sổ mới nhắc họ chi tiết của mục và xác nhận đầu vào khi họ nhấp vào 'OK'.

Tất cả điều đó chỉ hoạt động tốt. Tuy nhiên, tôi có một câu hỏi về quản lý bộ nhớ. Để tạo ra cửa sổ mới, tôi sử dụng đoạn mã sau:

- (IBAction)addNewItem:(id)sender { 
    LibraryItemEditorController *editorController = 
    [[LibraryItemEditorController alloc] 
      initWithWindowNibName:@"LibraryItemEditor"]; 

    [editorController showWindow:nil]; 
    // editorController is "leaked" here, it seems. 
} 

tôi không thể phát hành (và cũng không autorelease) editorController vào cuối addNewItem:, bởi vì không có gì khác là tham khảo editorController; nếu tôi thả nó ra, cửa sổ ngay lập tức biến mất. Tôi làm, tuy nhiên, muốn điều khiển cửa sổ được phát hành khi cửa sổ của nó được đóng lại. Trong của Window Programming Guide Apple, tôi đọc phần sau đây:

Nếu bạn muốn đóng một cửa sổ để làm cho cả cửa sổ và cửa sổ điều khiển biến mất khi nó không phải là một phần của một tài liệu , lớp con lại NSWindowController có thể quan sát NSWindowWillCloseNotification hoặc, như các đại biểu cửa sổ, thực hiện các phương pháp windowWillClose: và bao gồm các dòng mã sau đây trong thực hiện của bạn:

[self autorelease]; 

Tôi đã sử dụng [self autorelease] trong phương pháp windowWillClose: của trình điều khiển cửa sổ. Điều này làm việc, và không bị rò rỉ bộ nhớ. Tuy nhiên, nó chỉ cảm thấy xấu xí; addNewItem: trông giống như bộ nhớ bị rò rỉ và phân tích tĩnh cũng nghĩ như vậy. Tôi biết rằng nó thực sự được xử lý trong windowDidClose:, nhưng nó chỉ cảm thấy sai. Hơn nữa, bộ điều khiển cửa sổ hiện đang tự giải phóng mà không bao giờ giữ lại chính nó. Điều này tất cả đi ngược lại các quy tắc quản lý bộ nhớ mà tôi đã học được.

tùy chọn khác của tôi là để chấm Ivar trên bộ điều khiển cha mẹ (hoặc một NSWindowController hoặc một NSMutableSet của NSWindowController s) và sau đó xem cho NSWindowWillCloseNotification trong bộ điều khiển phụ huynh và thả nó trong phản ứng. Điều này là sạch hơn, và có lẽ là những gì tôi sẽ làm. Nó cũng là một số tiền công bằng nhiều công việc, mặc dù, dẫn tôi đến câu hỏi của tôi.

Đang xem cách NSWindowDidCloseNotification cách tiêu chuẩn để thực hiện việc này? Cách tiêu chuẩn quản lý NSWindowControllers được tạo ra và hủy theo yêu cầu là gì? Có phải cách [self autorelease] là tùy chọn được khuyến nghị theo truyền thống không và bây giờ chúng ta có phân tích tĩnh rằng đây có phải là vấn đề không?

Trả lời

5

Nghe có vẻ như cửa sổ của bạn là phương thức, trong trường hợp này:

[NSApp runModalForWindow:[editorController window]]; 
[editorController release]; 

Dưới đây là một mô hình cho các cửa sổ không modal:

@implementation QLPrefWindowController 

+ (id) sharedInstance 
{ 
    if (!_sharedInstance) 
    { 
     _sharedInstance = [[QLPrefWindowController alloc] init]; 
    } 
    return _sharedInstance; 
} 

- (void)windowWillClose:(NSNotification *)notification 
{ 
    if ([notification object] == [self window] && self == _sharedInstance) 
    { 
     _sharedInstance = nil; 
     [self release]; 
    } 
} 

Sau đó, bất cứ ai muốn truy cập hoặc hiển thị cửa sổ có thể làm như vậy thông qua phương thức lớp học +sharedInstance.Nếu cửa sổ không hiển thị, nó sẽ được tạo, nếu không thì cửa sổ hiện tại có thể nhìn thấy được.

+0

Tôi đã không chạy nó như là một cửa sổ phương thức, nhưng tôi nghĩ rằng tôi có lẽ nên. phiên bản sharedInstance có ý nghĩa đối với một bảng điều khiển thanh tra, tôi nghĩ vậy. Và nếu tôi thực sự cần phải mở nhiều cửa sổ cùng một lúc, có lẽ sẽ có ý nghĩa khi tôi giữ chúng trực tiếp. Điều này làm việc cho tôi. –

+0

Tôi không tin câu trả lời này là đúng, vì các phương thức lớp không thể truy cập các biến mẫu. Trong trường hợp này, phương thức lớp "sharedInstance" đang cố truy cập một iVar có tên là "_sharedInstance". Điều này sẽ thất bại mỗi lần. – Bryan

+0

'_sharedInstance' sẽ là một biến tĩnh, không phải là một ivar. Đó thường là cách các cá thể chia sẻ được thực hiện. –

0

Giải pháp cho các tình huống không phải là phương thức được đăng ở trên là không chính xác vì phương pháp lớp không thể truy cập iVars. Tôi giải quyết vấn đề này bằng cách tạo ra một phương thức lớp (subclass NSWindowController tôi gọi LPWindowController) trông như thế này:

+ (id) autoreleasingInstanceShowingWindow 
{ 
    LPWindowController *obj = [[LPWindowController alloc] initWithWindowNibName:@"myWindow"]; 
    [obj showWindow:[NSApp delegate]]; 

    return obj; 
} 

Phương pháp trên trả về một thể hiện của LPWindowController với một số giữ lại của 1. Nó cũng cho thấy cửa sổ của bộ điều khiển . Điều này là quan trọng, bởi vì nếu không chúng ta sẽ phải dựa vào người gọi để gọi "showWindow:" để làm cho cửa sổ LPWindowController xuất hiện. Nếu người gọi không bao giờ thất bại trong việc thực hiện điều này (có khả năng là lỗi), bộ điều khiển sẽ không bao giờ được phát hành. Bằng cách buộc cửa sổ hiển thị khi chúng tôi phân bổ/init bộ điều khiển, chúng tôi tránh sự cố này.

Tiếp theo, trong IB chúng tôi đặt đại biểu cửa sổ của chúng tôi để lớp LPWindowController và thêm này trong lớp đó:

- (void) windowWillClose:(NSNotification *)notification 
{ 
    [self autorelease]; 
} 

Và cuối cùng, khi chúng ta cần phải tạo ra và hiển thị cửa sổ của chúng tôi, chúng tôi chỉ đơn giản là sử dụng phương pháp dưới đây thay vì gọi "alloc/initWithWindowNibName:" trên LPWindowController.

LPWindowController *cont = [LPWindowController autoreleasingInstanceShowingWindow]; 
cont = nil; 

Dòng thứ hai là quan trọng. Đầu tiên, nó loại bỏ một cảnh báo về "biến không sử dụng tiếp". Thứ hai, nó giúp loại bỏ sự nguy hiểm của một con trỏ lơ lửng. Khi cá thể của bản phát hành LPWindowController chính nó, nếu tiếp theo không được điền vào, nó sẽ trỏ đến bộ nhớ rác.

Dù sao, đó là cách tiếp cận được đề xuất của tôi cho vấn đề này.

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