2009-06-08 181 views
1

我是C,Obj-C和iPhone的初學者,我正在嘗試使用很多術語,希望你們能幫助解決問題。現在已經掙扎了幾天在iPhone上泄漏內存:(

我的代碼是調用一個包含一個搜索字段和一個表的nib的方法,該表從下面爲'theList'創建的數組的搜索中填充。使用'儀器',我得到一個泄漏線: NSDictionary * theItem = [NSDictionary dictionaryWithObjectsAndKeys:clientName,@「Name」,clientId,@「Id」,nil];,但我不明白爲什麼: (

我知道這可能是一個難以回答的問題,但如果有的話可以有任何幫助!

- (void)editClient:(id)sender { 

    if (pickList == nil) { 
     pickList = [[PickFromListViewController alloc] initWithNibName:@"PickList" bundle:nil]; 
    } 

    TimeLogAppDelegate *appDelegate = (TimeLogAppDelegate *)[[UIApplication sharedApplication] delegate]; 
    NSMutableArray *theList = [[NSMutableArray alloc] init]; 
    int i; 
    for (i=0;i < [appDelegate.clients count];i++) { 
     Client *thisClient = [appDelegate.clients objectAtIndex:i]; 
     NSString *clientName = [[NSString alloc] initWithString: thisClient.clientsName]; 
     NSNumber *clientId = [[NSNumber alloc] init]; 
     clientId = [NSNumber numberWithInt:thisClient.clientsId]; 
     NSDictionary *theItem = [NSDictionary dictionaryWithObjectsAndKeys:clientName,@"Name",clientId,@"Id",nil]; 
     [theList addObject:theItem]; 
     theItem = nil; 
     [clientName release]; 
     [clientId release]; 
    } 
    [pickList createSearchItems:theList :NSLocalizedString(@"Client",nil)]; 
    [theList release]; 

    appDelegate.returningID = [NSNumber numberWithInt: projectsClientsId]; 
    [self.navigationController pushViewController:pickList animated:YES]; 

} 

提前感謝!

回答

9

這將返回分配的NSNumber實例。

NSNumber *clientId = [[NSNumber alloc] init]; 

這條線覆蓋與NSNumber的另一個實例以上的clientId,自動釋放的對象,因爲你還沒有爲它分配的內存,你不應該釋放呼叫numberWithInt返回時,它會自動釋放。

clientId = [NSNumber numberWithInt:thisClient.clientsId]; 

您正在調用clientId上的release版本,因此會出現內存問題。 要修復它除去第一線之上即在該情況下無用並更新第二個到:

NSNumber * clientId = [NSNumber numberWithInt:thisClient.clientsId]; 

然後取出:

[clientId release] 

由於的clientId將被自動解除。

編輯:重新仍然有問題...... 我不知道怎麼給你操縱的應用程序委託的客戶,否則代碼應工作正常,我創建了小例子,省略了,我可以在部分」看不到(應用程序委託和客戶端):

//命令行實用程序 - 基礎工具項目:

#import <Foundation/Foundation.h> 

int main (int argc, const char * argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    NSMutableArray * theList = [[NSMutableArray alloc] init]; 

    int i = 0; 
    for (i = 0; i < 10; ++i) 
    { 
     NSString * clientName = [NSString stringWithString:@"client"]; //no need to release 
     NSNumber * clientId = [NSNumber numberWithInt:i]; 
     NSDictionary * theItem = [NSDictionary dictionaryWithObjectsAndKeys: 
            clientName, @"name", 
            clientId, @"id", 
            nil]; 

     [theList addObject:theItem]; 
    } 

    for (id item in theList) for (id key in item) NSLog(@"%@ - %@", key, [item objectForKey:key]); 

    [theList release]; 
    [pool drain]; 
    return 0; 
} 
+0

謝謝你的時間!我確實按照你的建議使用了它,但改變了代碼,認爲它可以解決問題。現在它按照你的建議回來了,但是泄漏結果相同。我能否認爲問題出在被調用的筆尖之內? – Chris 2009-06-08 07:52:25

3

您正在創建clientID [[NSNumber alloc] init],然後立即用自動發佈的NSNumber實例[NSNumber numberWithInt]覆蓋它,然後稍後在您的代碼中發佈它,您不應該這樣做。擺脫[[NSNumber alloc] init]線和[clientId release]線,並應該修復它一點。

+0

非常感謝您的回答。我確實按照你的建議使用了它,但改變了代碼,認爲它可以解決問題。現在它按照你的建議回來了,但是泄漏結果相同。我能否認爲問題出在被調用的筆尖之內? – Chris 2009-06-08 07:52:29

1
從NSNumber的明顯的泄漏

之外,還有一些其他的東西我會解決這個問題可能有幫助。大部分都很小,但根據我對Objective-C的經驗,較少的代碼==更清晰的代碼,對於Bash或Perl等語言來說並非如此。 ;-)

- (void) editClient:(id)sender { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    if (pickList == nil) { 
    pickList = [[PickFromListViewController alloc] initWithNibName:@"PickList" bundle:nil]; 
    } 
    TimeLogAppDelegate *appDelegate = (TimeLogAppDelegate*)[[UIApplication sharedApplication] delegate]; 

    NSMutableArray *searchItems = [NSMutableArray array]; 
    NSMutableDictionary *itemDict = [NSMutableDictionary dictionary]; 
    for (Client *client in appDelegate.clients) { 
    [itemDict setObject:[client.clientsName copy]     forKey:@"Name"]; 
    [itemDict setObject:[NSNumber numberWithInt:client.clientsId] forKey:@"Id"]; 
    [searchItems addObject:[[itemDict copy] autorelease]]; 
    } 
    [pickList createSearchItems:searchItems :NSLocalizedString(@"Client",nil)]; 
    [self.navigationController pushViewController:pickList animated:YES]; 
    appDelegate.returningID = [NSNumber numberWithInt: projectsClientsId]; 
    [pool drain]; 
} 

有幾個神祕點,讓我懷疑:

  • for循環告訴PICKLIST做的東西的NSMutableArray剛過線。該方法應該保留新陣列,以及釋放舊陣列(如果存在)。如果你只是覆蓋指針,舊的數組將被泄漏。 (另外,這種方法的命名很差,匿名參數(一個沒有前面的文本的冒號)在Objective-C中是合法的,但是被認爲是非常不好的做法。似乎將選擇列表與導航控制器相關聯。如果是自定義代碼,確保指定一個新當-pushViewController:animated:方法正確釋放現有的選擇列表。
  • 分配給appDelegate.returningID被假定爲調用者調用returningID屬性。確保財產根據需要保留或複製NSNumber

內存泄漏可能會非常棘手追查,即使在儀器,你經常會發現它看起來像基礎類(如NSDictionary)正在泄漏像篩子,但我一直能追蹤到它回到我的代碼中的異常。 :-)