2

セッターで、次のように NSString を保持および解放することをお勧めします。

-(void) setName:(NSString *)newName
{
    if(newName != nil)
    {
         [newName retain]:
         [m_Name release];
         m_Name = newName; //Where m_Name is a NSString *
    }
    //I'm not sure for this code, I have difficulties understanding memory-management in ObjC
}

または、 NSMutableString を介して値を変更するには:

-(void) setName:(NSString *)newName
{
    if(newName != nil)
        [m_Name setString:newName]; //Where m_Name is a NSMutableString *
}

いずれかまたは両方の方法が正しくない場合は、お知らせください。

4

2 に答える 2

4

いくつかの考え:

  1. ベスト プラクティスは、自動的に合成されたアクセサー メソッドを利用するために、セッターをまったく作成しないことです)。独自のものを作成することは、メモリ管理を台無しにしたり、バグを導入したりする機会にすぎません。カスタム セッターを作成する前に、どうしてもカスタム セッターが必要である必要があります。

  2. インスタンス変数名の新たな慣例は、先頭にアンダースコアを付けたプロパティ名を使用することです (たとえば、 というプロパティnameの場合、ivar は です_name)。このステートメントを省略した場合@synthesize、最近のバージョンの Xcode に含まれているコンパイラがこれを自動的に行います。

  3. セッターがどうあるべきかという問題は、プロパティにどのようなメモリ修飾子があったかを述べていなければ意味がありません。プロパティを として定義したと仮定しますretain

  4. プロパティを a にNSMutableString変更すると、プロパティの動作が変更されます。何らかの理由で変更可能な文字列が本当に必要でない限り、お勧めしません。

  5. 誰かがnameプロパティを に設定した場合、最初の例は何もしませんnil。しかし、誰かがそれを に設定したい場合でも、(a) 古い値をnil解放する必要があります。name(b) ivar を に設定しますnil。(ちなみに、以下の私のコードは、nilオブジェクトにメッセージを送信しても何も起こらないという事実を利用しているためnil、この場合、メッセージがオブジェクトに送信されているかどうかを確認する必要はありません。)

したがって、次のように定義されたプロパティがあると仮定します。

@property (nonatomic, retain) NSString *name;

そして、省略されているか次のような合成行があります。

@synthesize name = _name;

次に、セッターは次のようになると思います。

-(void) setName:(NSString *)name
{
    // if you want to program defensively, you might want the following assert statement:
    //
    // NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__);

    if (name != _name)
    {
        [_name release];
        _name = name;
        [_name retain];
    }
}

ちなみに、あなたのinitメソッドが適切に初期化さ_nameれ、それdeallocが解放されると仮定します。

- (id)init
{
    self = [super init];
    if (self) {
        _name = nil;
    }
    return self;
}

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

bblum が指摘しているように、プロパティに使用するのが賢明copyですNSString

@property (nonatomic, copy) NSString *name;

次に、セッターは次のようになると思います。

-(void) setName:(NSString *)name
{
    // if you want to program defensively, you might want the following assert statement:
    //
    // NSAssert(name == nil || [name isKindOfClass:[NSString class]], @"%s: name is not string", __FUNCTION__);

    if (name != _name)
    {
        [_name release];
        _name = [name copy];
    }
}

しかし実際には、どうしても必要な場合を除き、セッターを作成するべきではありません。


最後に、コードには、メモリ管理がわかりにくいというコメントがあります。必ず理解する必要がありますが、最後に 2 つの提案をします。

  1. 自動参照カウント(ARC) の使用を検討してください。これにより、メモリ管理がどのように機能するかを理解する必要がなくなるわけではありませんが (『Advanced Memory Management Programming Guide』を参照)、メモリ管理を適切に処理するコードを簡単に記述できるようになります。手動参照カウント (MRC) コードを作成すると、単純なメモリ管理ミスが非常に発生しやすくなります。通常は ARC が対処します。

  2. 特に MRC を使用する場合は、Xcode の静的アナライザーを利用してください (「製品」メニューの「分析」またはshift+ command+を押しますB)。これにより、MRC コードを悩ませている多くの日常的なメモリ管理の問題を簡単に見つけることができます。Instruments User GuideFinding Memory Leaksセクションには、コードのデバッグ中にリークを見つける方法も示されていますが、多くの場合、スタティック アナライザーはコードを調べるだけで問題を特定できます。

于 2013-05-30T14:27:38.947 に答える
0

最初の解決策の方が優れています。これがretainプロパティの処理方法です。新しい値を保持してから、古い値を解放します。また、ケースのnil処理が重要でない場合は、 によって生成されるデフォルトの実装に依存できます@synthesize

2 番目の解決策については、これは本当に不必要であり、慣習に少し反します。また、このソリューションでは、m_name文字列を割り当てる前に初期化する必要があります。でそれを行うことができますinit

- (void) init {
    if (self = [super init]) {
        m_name = [[NSMutableString alloc] init];
    }
}

結論:最初の解決策は間違いなく優れています。

于 2013-05-30T14:00:45.413 に答える