2009-06-08 4 views
1

私はC、Obj-C、iPhoneの初心者で、多くの用語が使用されています。iPhoneでメモリがリークしている:(

以下のコードは、検索フィールドとテーブルを含むnibを呼び出すメソッドです。テーブルは、以下の 'theList'のために作成された配列から検索されます。 NSDictionary * theItem = [NSDictionary dictionaryWithObjectsAndKeys:clientName、@ "Name"、clientId、@ "Id"、nil];しかし、私は理由を把握することができません: 'Instruments'を使用して、私はリークをラインで取得しています : (

私はそれはおそらく答えが難しい質問ですが、 1つはどんな助けでもかまいません!

- (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を呼び出しています。この場合には無用である上記の最初の行を削除し、第一更新それを修正する :のclientIdが自動的に解放されるので

[clientId release] 

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

を次に除去。

EDIT:まだ問題を抱えている再... は、私はそれ以外のコードは私ができる部分を省略し、[OK]を、私は小さな例を作成し動作するはずです、あなたにアプリのデリゲート内のクライアントを操作するかどうかはわかりません」基盤ツールプロジェクト -

//コマンドラインユーティリティ:

#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

+0

あなたは何を得ているのですか? – stefanB

+0

NSCFDictionary、NSCFArray&GeneralBlock-16があり、その1行を参照しています。あなたが見る通り、私はメソッドの最後に新しいViewControllerを押します。そこにはMutableCopyを使って2つのMutableArraysを作成してTableViewの検索を実行します - 私は深いコピーを実行していませんので、MutableCopiesはまだ同じオブジェクトペア?これらの2つの配列は、一度終了したViewController内で明らかに解放されます。あなたの時間と助けにもう一度感謝します。 – Chris

3

[[NSNumber alloc] init]を使用してclientIDを作成していて、すぐに自動解放されたNSNumberインスタンス[NSNumber numberWithInt]で上書きした後で、コードで後で解放する必要があります。 [[NSNumber alloc] init]行と[clientId release]行を取り除いて、少し修正してください。

+0

あなたの答えに多くの感謝。私はあなたが示唆したとおりに実際にそれを持っていましたが、そのコードを変更して問題を解決できるかもしれないと考えました。あなたの提案通りに戻ってきましたが、同じリーク結果があります。問題は、呼び出されたペン先の中にあると思いますか? – Chris

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]; 
} 

私は不審にするいくつかの神秘的なポイントがあります。

  • ラインは、直後のループのためにNSMutableArrayのと何かをピックリストに指示します。その方法は新しい配列を保持し、は古い配列をリリースする必要があります。ポインタを上書きするだけで、古い配列がリークします。 Objective-Cでは、匿名の引数(先行するテキストがないコロン)は合法ですが、非常に悪い習慣とみなされます。
  • 次の行ピックリストをナビゲーションコントローラに関連付けるように見える。それがカスタムコードである場合は、-pushViewController:animated:メソッドが、新しいものが指定されたときに既存の選択リストを適切に解放するようにしてください。
  • appDelegate.returningIDに代入すると、returningIDプロパティのセッターが呼び出されます。プロパティは、必要に応じてNSNumberを保持またはコピーすることを確認してください。

メモリリークがさえインスツルメンツでは、追跡するトリッキーなことができ、あなたは、多くの場合、それはふるいのようにリークしている財団クラス(例えばNSDictionaryをなど)のように見えることがわかりますが、私は常にトレースすることができました私のコードの異常に戻ります。 :-)

関連する問題