2009-08-27 13 views
2

私はObjective-Cを新しくしました。私は、以下に示すローカルのNSString変数とクラスオブジェクト内の関連するインスタンス変数のメモリをどのように管理する必要があるのか​​少し不思議です。私のコードはうまく動作しますが、ベストプラクティスについては興味があります。NSString用にメモリを割り当てていますか?

完全なコードを含めるように編集しましたが、この文脈ではNSStringオブジェクトに対してalloc/releaseを実行する必要があるかどうかは不思議です。

// MAIN ------------------------------------------------------------------- ** 
#import <Foundation/Foundation.h> 
#import "PlanetClass.h"; 

int main (int argc, const char * argv[]) { 

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    NSString *planet_01_Geek; 
    NSString *planet_02_Geek; 

    // Create planets 
    PlanetClass *newPlanet_01 = [[PlanetClass alloc] init]; 
    [newPlanet_01 setGeekName:@"StarWars"]; 
    PlanetClass *newPlanet_02 = [[PlanetClass alloc] init]; 
    [newPlanet_02 setGeekName:@"Dune"]; 

    // Query a planet 
    planet_01_Geek = [newPlanet_01 geekName]; 
    planet_02_Geek = [newPlanet_02 geekName]; 

    // Print details 
    NSLog(@"Planet Geek = %@", planet_01_Geek); 
    NSLog(@"Planet Geek = %@", planet_02_Geek); 

    // Clean up 
    [newPlanet_01 release]; 
    [newPlanet_02 release]; 
    [pool drain]; 
    return 0; 
} 

..

// CLASS HEADER ----------------------------------------------------------- ** 
#import <Foundation/Foundation.h> 

@interface PlanetClass : NSObject { 
NSString *geekName; 
} 

- (NSString*) geekName; 
- (void) setGeekName:(NSString*)gName; 
@end 
// ------------------------------------------------------------------------ ** 

..あなたが設定 "geekName" の性質を持っているかに依存するであろう

// CLASS BODY ------------------------------------------------------------- ** 
#import "PlanetClass.h" 

@implementation PlanetClass 

- (NSString*)geekName { 
    return geekName; 
} 
- (void)setGeekName:(NSString*)gName { 
    geekName = gName; 
} 
@end 
// ------------------------------------------------------------------------ ** 

答えて

8

memory management rulesをお読みください。あなたが知る必要があるすべてを説明する9つの簡単な段落。

geekNameは "alloc"または "new"で始まらないか、または "copy"を含んでいるため、 "所有していない"文字列を返す必要があります。したがって、あなたはそれを解放する必要はありません(そして、そうする必要はありません)。また、その参照を保存してはいけません。現在のメソッドから返すこともできます。この場合、メソッド名も "alloc"または "new"で始まらないか、または "copy"を含むべきではありません。

あなたがそれを守りたいのであれば、retainを呼び出すことによってオーナーシップを取る必要があります。あるいは、そのNSStringがより良いコピーであるためです。これはコピー/保持プロパティに割り当てると自動的に行われることがあります。

あなたが今転記したコードでは、あなたの設定者に誤りがありました。

- (void) dealloc 
{ 
    [geekName release]; 
    [super dealloc]; 
} 

また、あなたはObjective Cのプロパティを使用することができます:あなたは、その後もgeekNameを放出するのdeallocルーチンを必要とする

- (void)setGeekName:(NSString*)gName { 
    if (geekName != gName) { 
     [geekName release]; 
     geekName = [gName copy]; 
} 

:あなたのセッターは次のように入力パラメータのコピー、何かを取るべきです。

- (NSString*) geekName; 
- (void) setGeekName:(NSString*)gName; 

プロパティを使用します:

@property (nonatomic, copy) NSString* geekName; 

、代わりにセッターとゲッターの実装の、システムはあなたのためにそれらを合成してみましょう:

@synthesize geekName; 

代わりにあなたのインターフェース上映のgeekNameを解放するにはまだdeallocメソッドが必要です。

2

。コピーを作成するのではなく、クラス内の既存のメンバーへの参照を返すだけだと思いますか?そのような場合は、コード内に何かをリリースすることについて心配する必要はありません。

あなたはそれがであるクラスの()にdeallocで「geekName」メンバーの解放を心配する必要がありますする必要があります。

+0

私が見るには、私のクラスのインタフェースは以下の通りですので、あなたのことわざは、私は本当にないクラスのdeallocメソッドを持っているべきものです[geekNameリリース];私はplanetClassオブジェクト放出されたとき、それが解放される可能性があります考えていた(つまり、[newPlanet_01リリース];) @interfaceのPlanetClass:NSObjectの{ \tフロート重力; \tフロート質量; \tのchar *名; \t NSString * geekName; \t } 乾杯ゲーリー – fuzzygoat

+0

@fuzzygoat - その文字列を元々どのように割り当てたかによって異なります。 alloc()やそれに類するものを使用した場合は、それを解放する必要があります。静的な "引用符付きの文字列"から割り当てた場合、解放する必要はありません。 –

0

変数は無料です。ローカル変数は、コンパイラによって割り当てられます。インスタンス変数は、インスタンスの一部としてランタイムによって割り当てられます。

変数にポインタを入れたオブジェクトは空きではありません。それらを解放する必要があるかもしれません。オブジェクトを解放する必要があるかどうかは、the rulesによって決まります。

0

2つのローカル変数をどのように使用しているかによって、さらにメモリ管理が必要になることがあります。

コードの読み方では、ローカル変数を2つのクラスオブジェクトから返されるポインタに設定しています。 newPlanet*クラスを正しく記述した場合は、クラスを解放するときに文字列オブジェクトを解放する必要があります。

1として明示的に

文字列を保持:あなたの2つのローカル変数が、その後、ポインタを使用しようとするオブジェクトがTHERもはや

二つの可能な修正されないよう、あなたは問題があるでしょうローカル変数が直接割り当てられている、あなたは本当に、明示的にオブジェクトを保持している必要があります。

planet_01_Geek = [[newPlanet_01 geekName] copy]; 
planet_02_Geek = [[newPlanet_02 geekName] copy]; 

それはホールドを保つための好ましい方法ですので、私はここにコピーを指定しています変更可能なオブジェクトの場合は、元の変更がある場合は、ローカル変数も変更されます。

2.特性(好ましい)

これは私の好ましい方法であろう:インスタンス変数のretaincopy、またはassignは、クラスによって処理されます。

はすなわち、正しくプロパティを宣言します。

@property (nonatomic, copy) NSString *planet_01_Geek; 
@property (nonatomic, copy) NSString *planet_02_Geek; 

使用@synthesize実装に。

次に、プロパティ構文を使用して変数を割り当てます。

self.planet_01_Geek = [newPlanet_01 geekName]; 
self.planet_02_Geek = [newPlanet_02 geekName]; 

正しいメモリ管理ルールが割り当てに適用され、合成されたアクセサメソッドは、現在のローカル変数に割り当てられている任意のオブジェクトを解放するの世話をしますこの方法です。

編集 - ノートあなたがメモリをリークしているあなたのsetGeekName:方法で

を示し、さらにクラスの詳細以来。新しいポインタをローカル変数に割り当てると、そこにあったオブジェクトへのリリースは送信されません。それを行うには良い方法(それをシンプルに保つためにretainではなくcopyを使用して:

- (void)setGeekName:(NSString *)gName { 
    [gName retain]; // Hold on to the object that is passed in. 
    [geekname release]; // Let go of your current object. 
    geekName = gName; // Now allocate the new object. 
} 
+0

こんにちはAbizern、私はちょうどコード(その唯一の初期の学習のもの)をトリムし、上の全体を投稿した。私はちょうど今あなたの返信を読んでいる、多くのありがとう。 – fuzzygoat

+0

私はちょうど始めました(先週は正確です)、私は@合成とプロパティについて知っていますが、まだ見ていない限り、私は彼らが第9章にいると思います、私はまだ3です:) – fuzzygoat

+0

大丈夫;あなたがその部分に着いたら、これを覚えておいてください。 – Abizern