2011-11-10 101 views
2

我收到一個分析器泄漏,但是這是我在別處沒有問題使用的相同代碼。我知道我使用的是alloc,因此我必須釋放,但我在dealloc中這樣做。Obj-C,在線分配的對象的潛在泄漏,UIBarButtonItem alloc

我在做什麼錯?

頭文件

@interface myViewController : UIViewController <UITableViewDataSource, 
       UITableViewDelegate> { 

    UIBarButtonItem *addButton; 
} 
@property (nonatomic, retain) UIBarButtonItem *addButton; 

主文件:

@synthesize addButton; 
- (void)viewDidLoad { 

    NSMutableArray* buttons = [[NSMutableArray alloc] initWithCapacity:3]; 


    addButton = [[UIBarButtonItem alloc] 
          initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 
          target:self action:@selector(btnNavAddPressed:)]; 
    addButton.style = UIBarButtonItemStyleBordered; 
    [buttons addObject:addButton]; 

    [tools setItems:buttons animated:NO]; 
    [buttons release]; 

    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] 
           initWithCustomView:tools]; 

    addButton.enabled = FALSE; 

- (void)dealloc { 
    [addButton release]; 

回答

1

以上兩個答案都有誤導性。您不需要使用setter,將對象直接分配給iVars是完全正確的。您確實需要釋放您分配或保留的任何內容。你有問題就在這裏:

self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:tools]; 

此行alloc'ing一個UIBarButtonItem實例,並將它設置爲navigationItemrightBarButtonItem財產。這意味着navigationItem正在保留UIBarButtonItem,它負責保留。你有責任釋放它的alloc的B/C,你不是。將代碼更改爲:

self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:tools] autorelease]; 

並且此泄漏消失。

+1

這些類型的問題是iOS開發人員最常見的障礙之一。當你獲得經驗時,它變得更容易/更自然。如果您使用的是xcode 4.2,我建議閱讀ARC(自動引用計數)上的文檔並將您的項目遷移到該文檔。它不會更改規則WRT內存管理,但它確實允許編譯器爲您執行幾乎所有的工作。 – XJones

2

您未使用的setter,代碼應該是:

self.addButton = [[[UIBarButtonItem alloc] 
         initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 
         target:self action:@selector(btnNavAddPressed:)] autorelease]; 

這種類型的問題,可避免通過使用名稱不同於財產名稱的伊娃。這是在@synthesize語句完成的:

@synthesize addButton = _addButton; 

這樣的self任何疏漏都會導致錯誤消息。

這是一個完整的實現(除tools是不確定的),物業Add按鈕是在所有地方手柄:

@interface myViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> { 
} 
@property (nonatomic, retain) UIBarButtonItem *addButton; 
@end 

@implementation myViewController 
@synthesize addButton = _addButton; 

- (void)viewDidLoad { 
    NSMutableArray* buttons = [NSMutableArray array]; 

    self.addButton = [[UIBarButtonItem alloc] 
       initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 
       target:self action:@selector(btnNavAddPressed:)]; 
    self.addButton.style = UIBarButtonItemStyleBordered; 
    [buttons addObject:self.addButton]; 

    [tools setItems:buttons animated:NO]; 

    self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:tools] autorelease]; 

    self.addButton.enabled = FALSE; 
} 
- (void)dealloc { 
    [_addButton release]; 
} 
@end 
+0

這不會給內存泄漏嗎? (自ARC以來,這些評論變得更加困難!) – jrturton

+0

@jrturton糟糕,回答問題。謝謝!當然在ARC下不需要autorelease。 – zaph

+0

這就是我的意思,它曾經很容易發現泄漏,現在有一個額外的層。我更喜歡過去的美好時光...... – jrturton

2

當您使用屬性,並指定給它指定確定retainCount是否增加的屬性如果您分配給該屬性。在你的情況下,你指定了「retain」這意味着處理賦值給你屬性的setter函數將自動增加對象的保留計數。

但是當你寫

addButton = [[UIBarButtonItem alloc] 
          initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 
          target:self action:@selector(btnNavAddPressed:)]; 

要創建opject與已經保持數== 1,所以當你分配給它會保留計數2.正確的方式做,這是創建一個臨時變量並創建該對象,然後將該temp變量分配給該屬性,然後釋放該temp。變量:

UIBarButtonItem* tmp = [[UIBarButtonItem alloc] 
          initWithBarButtonSystemItem:UIBarButtonSystemItemAdd 
          target:self action:@selector(btnNavAddPressed:)]; 
self.addButton = tmp; 
[tmp release]; 

當然,我會推薦一個比'temp'更具描述性的名稱作爲變量名稱。

+0

這是誤導性建議。 OP的代碼爲''addButton''就好。他正確地將分配的對象直接存儲在iVar中,並在'dealloc'中釋放它。 – XJones

0

您沒有利用聲明的屬性,但我沒有看到addButton的任何問題。該泄漏似乎更多在:

self.navigationItem.rightBarButtonItem = 
          [[UIBarButtonItem alloc] initWithCustomView:tools]; 

只需添加autorelease泄漏將消失。

+0

這很奇怪,我複製了你的代碼,缺少autorelease是我和分析器發現的唯一問題。清理和分析?或者你可以發佈分析器屏幕截圖(帶箭頭的那個)? – djromero