web-dev-qa-db-ja.com

@synthesized保持プロパティのリリースはどのように処理されますか?

Objective-Cの合成プロパティについて質問があります。完全なリストは次のとおりですが、基本的な質問は次のとおりです:コードがdeallocにリリースメソッドを含めるかどうかにかかわらず、コンパイラは合成プロパティのivarが適切にリリースされることをどのように保証しますか?

注:これらは個別の質問として投稿しないことにしました。それらは非常に密接に関連しており、実際には心に届かずに個々の問題に触れる少数の既存の質問があるためです。問題の。

やや似た質問:


Setup:単一のプロパティを持つクラスを考えます:

@interface Person : NSObject
{
    NSString * name;
}
@property (nonatomic, retain) name;
@end

質問#1:非常に基本的なケース:

@implementation Person
@synthesize name;
@end

この設定では、nameオブジェクトが解放されるたびにPersonが自動的に解放されると想定しています。私の考えでは、コンパイラーはdeallocメソッドに[name release]を挿入するだけで、まるで自分で入力したかのように処理します。あれは正しいですか?


質問#2:このクラスに独自のdeallocメソッドを記述することを選択し、[name release]への呼び出しを省略した場合、リーク?

@implementation Person
@synthesize name;
- (void)dealloc { [super dealloc]; }
@end

質問#3:このクラス用に独自のdeallocメソッドを作成することを選択し、includeした場合[name release]への呼び出しは、@synthesizeがすでに処理してくれているので、二重解放になりますか?

@implementation Person
@synthesize name;
- (void)dealloc { [name release]; [super dealloc]; }
@end

質問#4:このクラスの独自のプロパティアクセサーを作成することを選択したが、しない場合独自のdeallocメソッドを記述します。nameはリークされますか?

@implementation Person
@dynamic name;
- (void)setName:(NSString *)newName
{
    [newName retain];
    [name release];
    name = newName;
}
@end

質問#5:上記のシナリオのなしは(経験に基づいて)感じます言語はそれらを回避するように設計されているので、リークまたは二重リリースが発生します。もちろん、それは「どうやって?」の問題を提起します。コンパイラーは、考えられるすべてのケースを追跡するのに十分スマートなだけですか?以下を実行するとどうなりますか(これはばかげた例であり、私のポイントを説明するためだけのものです)。

void Cleanup(id object) { [object release]; }

@implementation Person
@synthesize name;
- (void)dealloc { Cleanup(name); }
@end

コンパイラをだまして、別の[name release]deallocメソッドに追加しますか?

65
e.James

Q1:

いいえ。@synthesize-deallocを変更することはありません。 -release the name自分でする必要があります。

Q2:

はい、漏れます。 Q1と同じ理由。

Q3:

いいえ、それはダブルリリースされません。 Q1と同じ理由。

Q4:

はい、漏れます。 Q1と同じ理由。

Q5:

いいえ、それはダブルリリースされません。 Q1と同じ理由。


これを自分で確認するには、-retain-release-deallocをオーバーライドして、進行状況を報告します。

#import <Foundation/Foundation.h>

@interface X : NSObject {}
@end
@implementation X
-(oneway void)release {
        NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1);
        [super release];
}
-(id)retain {
        NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1);
        return [super retain];
}
-(void)dealloc {
        NSLog(@"Dealloc %p", self);
        [super dealloc];
}
@end

@interface Y : NSObject {
        X* x;
}
@property (nonatomic, retain) X* x;
@end
@implementation Y
@synthesize x;
- (void)dealloc { [x release]; [super dealloc]; }
@end

int main () {
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
        Y* y = [[Y alloc] init];
        X* x = [[X alloc] init];
        y.x = x;
        [y release];
        [x release];
        [pool drain];                                                    
        return 0;
}

Q1、Q2、Q4では、xの最後の-retainCountが1であるため、リークがあり、Q3とQ5では、最後の-retainCountは0と-deallocです。が呼び出されるので、リークはありません。

57
kennytm

プロパティに関するObjective-Cのドキュメント から:

割り当て解除

宣言されたプロパティは、基本的にアクセサメソッド宣言の代わりになります。プロパティを合成するとき、コンパイラは存在しないアクセサメソッドのみを作成します。 deallocメソッドとの直接的な相互作用はありません。プロパティは自動的に解放されません。ただし、宣言されたプロパティは、deallocメソッドの実装をクロスチェックする便利な方法を提供します。ヘッダーファイルですべてのプロパティ宣言を探し、割り当てとマークされていないオブジェクトプロパティが解放され、割り当てとマークされているオブジェクトプロパティが解放されていることを確認できます。リリースされていません。

これは基本的にすべての質問に答えます。

17
Dave

シンプルで一般的なルール:オブジェクトを割り当て、保持、またはコピーする場合、ユーザーはオブジェクトを解放する必要があります。

_@synthesize_ステートメントでretainセッターセマンティック設定を使用する場合、オブジェクトに対してretainを呼び出すセッターをビルドするようコンパイラーに要求します。それ以上でもそれ以下でもありません。そして、あなたはそのオブジェクトを保持しているので(たとえそれが魔法のように自動生成されたコードによってであっても)、それを解放する必要があり、解放する場所は-(void)deallocにあります。

8
Dan Ray

知っておく価値のある何か-合成されたプロパティがある場合、そのプロパティをnilに設定すると(もちろんドット構文を使用)、ivarが解放されます。

2
Adam