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
メソッドに追加しますか?
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
です。が呼び出されるので、リークはありません。
プロパティに関するObjective-Cのドキュメント から:
割り当て解除
宣言されたプロパティは、基本的にアクセサメソッド宣言の代わりになります。プロパティを合成するとき、コンパイラは存在しないアクセサメソッドのみを作成します。 deallocメソッドとの直接的な相互作用はありません。プロパティは自動的に解放されません。ただし、宣言されたプロパティは、deallocメソッドの実装をクロスチェックする便利な方法を提供します。ヘッダーファイルですべてのプロパティ宣言を探し、割り当てとマークされていないオブジェクトプロパティが解放され、割り当てとマークされているオブジェクトプロパティが解放されていることを確認できます。リリースされていません。
これは基本的にすべての質問に答えます。
シンプルで一般的なルール:オブジェクトを割り当て、保持、またはコピーする場合、ユーザーはオブジェクトを解放する必要があります。
_@synthesize
_ステートメントでretain
セッターセマンティック設定を使用する場合、オブジェクトに対してretain
を呼び出すセッターをビルドするようコンパイラーに要求します。それ以上でもそれ以下でもありません。そして、あなたはそのオブジェクトを保持しているので(たとえそれが魔法のように自動生成されたコードによってであっても)、それを解放する必要があり、解放する場所は-(void)dealloc
にあります。
知っておく価値のある何か-合成されたプロパティがある場合、そのプロパティをnilに設定すると(もちろんドット構文を使用)、ivarが解放されます。