2011-03-12 60 views
1

假設我有這樣一個接口:目標C一個簡單的問題,關於內存泄露

@interface it:NSObject 
{ 
    NSString* string; 
} 
@end 

@implement it 
-(id)init 
{ 
    if(self = [super init]){ 
    self.string = [[NSString alloc]init]; 
    } 
} 

-(void)dealloc 
{ 
    [self.string release]; 
    [super release]; 
} 
@end 

如果我在另一個文件中使用這個類,我稱之爲:

it ait = [[it allow] init]; 
NSString* anotherString = [[NSString alloc] init]; 
ait.string = anotherString; 
[anotherString release]; 

這樣會造成該字符串在init方法中被分配了內存泄漏? 由於該字符串未被引用且未被自動釋放。 如果我不在init方法中分配一個字符串,那麼在將anotherString賦值給它之前,我會調用ait.string會發生什麼?

回答

1

我想你需要

@property (nonatomic, retain) NSString *string; 
在你的界面

@synthesize string; 

在實施self.string工作。

然後,當你在你的init方法做

self.string = [[NSString alloc] init]; 

字符串實際上將有2因爲[[NSString alloc] init]會返回一個字符串,以1:1的保留計數一個保留計數,並使用self.string =將保留對象再次因爲該財產被宣佈爲'保留'。這將導致內存泄漏,但是您可以通過以下方式進行修復:

-(id)init 
{ 
    if(self = [super init]){ 
    self.string = @"initString"; 
    } 
} 

或類似內容。

然後,在實際的問題,如果你這樣做,當您與self.string =重新分配,因爲屬性標記爲「保留」保留新的前釋放他們的當前對象的init不會泄漏分配上面的字符串。

如果你不在init方法中給self.string分配一個字符串,這並不重要,因爲self.string只會返回nil,然後你可以在你的程序中處理它。

+0

另外,在dealloc中,它應該是'self.string = nil;'釋放字符串(或'[string release];'but * not *'[self.string release];')。 – DarkDust 2011-03-12 09:47:35

+1

大多數時候你想要一個字符串的複製屬性,而不是保留。 – Eiko 2011-03-12 10:12:01

0
@interface it:NSObject 
{ 
    NSString* string; 
} 

//you should declare a property in order to call it with 'self' prefix 
@property (nonatomic, retain) NSString* string; 

@end 


@implementation it 

//you should synthesize your property 
@synthesize string; 

-(id)init 
{ 
    if(self = [super init]){ 
    //you don't to initialize NSString right here (memory leak will have place) 
    //self.string = [[NSString alloc]init]; 

    //you can store a default value like this (can be omitted): 
    self.string = @"Default value"; 
    } 
    return self; 
} 

-(void)dealloc 
{ 
    [self.string release]; 
    [super release]; 
} 
@end 

關於這個類的內存管理的一切都會很好。

+0

...'return self;' – 2011-03-12 09:13:20

+0

沒錯,謝謝。編輯 – knuku 2011-03-12 09:53:10

0

會不會做它 init方法內存泄漏alloced字符串?由於 字符串未被引用,並且不是 自動釋放。

是的,正好。你似乎已經明白了。

如果我不ALLOC在init方法 一個字符串,會當我打電話 ait.string權利之前分配 anotherString它會怎麼樣呢?

你在下列情況下,意味着你無法確定是什麼unknownObject將涉及到: -

It *ait = [[It allow] init]; 
NSString *unknownObject = ait.string; 

這完全是無稽之談。你忘了添加訪問器方法嗎?

Objective-c不使用'點語法'來訪問實例變量,比如Java。如果您有一個類「實例」的實例,則只能通過調用訪問器的「getter」方法訪問實例以外的「字符串」變量。這不是可選self.string只是方法調用[self string]的快捷方式,並且此方法在您顯示的代碼中不存在。

假設存取方法在別處定義的,該實例變量你稱爲字符串(這是世界上最嚴重的變量名)等於。在Objective-c中,你必須非常小心地對待零對象,因爲行爲與多少其他語言處理類似的對象null

在Objective-C,這是好的:

NSString *nilString = nil; 
[nilString writeToFile:@"/this_file_cannot_exist.data"]; 

許多其他語言會在這裏崩潰或拋出一個異常;這可能很危險,因爲操作可能會失敗,但您的應用將繼續運行。它也可以是偉大的壽,因爲在其他語言中,你會看到很多這個..

someObject = controller.currentValue() 
if(someObject!=null) 
    someObject.writeToFile("myFile.data") 

在Objective-C的「如果(..)」行完全沒有必要的。

您必須小心,不要在init和dealloc方法中調用存取方法,因爲這會破壞子類。取而代之的

- (void)dealloc { 
    [self.string release]; // This is [[self string] release] 
    ... 

,你應該只使用

- (void)dealloc { 
    [string release]; 
    ... 

除了作爲危險調用[自字符串]是不必要的。同樣是真正的在你的init方法

if(self=[super init]){ 
    self.string = [[NSString alloc]init]; // shortcut for [self setString:[[NSString alloc] init]] 
    ... 

只使用

if(self=[super init]){ 
    string = [[NSString alloc] init]; 
    ... 
+0

Objective-C **使用點語法:訪問屬性。它可以是'self.string = nil;'或只是'[string release];'在dealloc中。前者通過屬性釋放,後者通過相關的實例變量釋放。 – DarkDust 2011-03-12 09:46:14

+0

我沒有說它沒有,我說它不使用'點語法'來訪問實例變量 - 這是非常不同的。另外self.string = nil在dealloc中是不好的,不要這樣做。 – hooleyhoop 2011-03-12 09:58:11

+0

在仔細閱讀關於點語法的段落時,我注意到我誤解了你寫的內容。我覺得它有誤導性。我從來沒有聽說,分配給dealloc中的一個屬性應該是不好的,請賜教我爲什麼這是一個壞主意。 – DarkDust 2011-03-12 14:24:23

0

你錯過了@property才能使用self.string。

添加到您的.h文件中

 
@property (readwrite, copy) NSString *string; 

使用,而不是保留將防止內存泄漏,即使釋放anotherString字符串複製。