83

私の知る限り、XCode 4.4 以降で@synthesizeは、プロパティ アクセサーが自動生成されます。しかし、ちょうど今、 に関するコードのサンプルを読んだところ、コード内でが明示的に追加されNSUndoManagerていることに気付きました。@synthesizeお気に入り:

@interface RootViewController  ()

@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSUndoManager *undoManager;

@end

@implementation RootViewController
//Must explicitly synthesize this
@synthesize undoManager;

私は今困惑しています...@synthesizeコードに明示的に追加する必要があるのはいつですか?

4

7 に答える 7

182

たくさんの答えがありますが、大きな混乱もあります。私はいくつかの順序を設定しようとします (または混乱を増やします, 見てみましょう...)

  1. Xcode の話はやめましょう。Xcode はIDEです。clang はコンパイラです。ここで説明しているこの機能は、プロパティの自動合成と呼ばれ、Xcode で使用される既定のコンパイラである clang でサポートされているObjective-C 言語拡張です。
    Xcode で gcc に切り替えた場合、(Xcode のバージョンに関係なく) この機能のメリットはありません。同様に、テキスト エディターを使用し、コマンド ラインから clang を使用してコンパイルすると、意思。

  2. 自動合成のおかげで、コンパイラによって次のように自動的に合成されるため、プロパティを明示的に合成する必要はありません。

    @synthesize propertyName = _propertyName
    

    ただし、いくつかの例外があります。

    • カスタム getter および setter を使用した readwrite プロパティ

      ゲッターとセッターの両方のカスタム実装を提供する場合、プロパティは自動的に合成されません

    • カスタム getter を使用した読み取り専用プロパティ

      読み取り専用プロパティのカスタム getter 実装を提供する場合、これは自動的に合成されません

    • @動的

      を使用する場合、プロパティは自動的に合成されません (とは相互に排他的である@dynamic propertyNameため、明らかです)。@dynamic@synthesize

    • @protocol で宣言されたプロパティ

      プロトコルに準拠する場合、プロトコルが定義するプロパティは自動的に合成されません

    • カテゴリで宣言されたプロパティ

      これは、@synthesizeディレクティブがコンパイラによって自動的に挿入されない場合ですが、このプロパティを手動で合成することもできません。カテゴリはプロパティを宣言できますが、カテゴリは ivar を作成できないため、まったく合成できません。完全を期すために、Objective-C ランタイムを使用してプロパティ合成を偽装することはまだ可能であることを付け加えておきます。

    • オーバーライドされたプロパティ(clang-600.0.51 以降の新機能、Xcode 6 に付属、Marc Schlüpmann に感謝)

      スーパークラスのプロパティをオーバーライドするときは、明示的に合成する必要があります

プロパティを合成すると、バッキング ivar が自動的に合成されることに注意してください。したがって、プロパティ合成が欠落している場合、明示的に宣言されていない限り、ivar も欠落します。

最後の 3 つのケースを除いて、プロパティに関するすべての情報を (すべてのアクセサ メソッドを実装するか、または を使用して@dynamic) 手動で指定すると、コンパイラはプロパティを完全に制御したいと想定し、プロパティの自動合成を無効にします。それ。

上にリストされているケースとは別に、明示的な唯一の他の使用法は@synthesize、別の ivar 名を指定することです。ただし、慣例は重要であるため、常にデフォルトの命名を使用することをお勧めします。

于 2013-11-06T20:10:52.987 に答える
16

@synthesizeコードに明示的に追加する必要があるのはいつですか?

通常、必要な場合: 必要なケースに遭遇することはおそらくないでしょう。

ただし、役立つ場合が 1 つあります。

カスタムの getter と setter の両方を作成していて、インスタンス変数でそれをサポートしたいとします。(アトミック プロパティの場合、これはカスタム セッターが必要なのと同じくらい簡単です。単原子プロパティのセッターを指定し、アトミック プロパティを指定しない場合、コンパイラはゲッターを書き込みます。)

このことを考慮:

@interface MyObject:NSObject
@property (copy) NSString *title;
@end

@implementation MyObject

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

存在しないため、これ_titleは機能しません。ゲッターまたはセッターの両方を指定したため、Xcode は (正しく) バッキング インスタンス変数を作成しません。

ここに画像の説明を入力

存在させるには 2 つの選択肢があります。を次のように変更できます@implementation

@implementation MyObject {
    NSString *_title;
}

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

または、これを次のように変更します。

@implementation MyObject

@synthesize title = _title;

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

つまり、synthesize は実際には決して必要ではありませんが*、getter/setter を提供するときにプロパティ バッキング インスタンス変数を定義するために使用できます。ここで、使用するフォームを決定できます。

以前は、 でインスタンス変数を指定することを好んでいましたが、冗長な型を削除し、バッキング変数をプロパティに明示的に関連付けるため、ルートの方が適切な選択である@implementation {}と考えています。@synthesize

  1. プロパティの型を変更すると、インスタンス変数の型が変更されます。
  2. そのストレージ修飾子を変更すると (たとえば、strong の代わりに weak にするか、weak の代わりに strong にする)、ストレージ修飾子が変更されます。
  3. プロパティを削除または名前変更すると@synthesize、コンパイラ エラーが発生します。迷子のインスタンス変数になってしまうことはありません。

*-複数のファイルのカテゴリ間で機能を分割することに関連して、必要なケースを 1 つ知っています。そして、Apple がこれを修正したとしても、あるいはすでに修正したとしても、私は驚かないでしょう。

于 2013-11-05T17:42:40.383 に答える
1

プロパティがプロトコルで宣言されている場合、プロパティ合成が必要です。インプリメンテーション インターフェイスでは自動的に合成されません。

于 2013-11-06T20:20:08.210 に答える
0

それを明確にしてくれてありがとう。同様の問題がありました。

@synthesize firstAsset, secondAsset, audioAsset;
@synthesize activityView;

それで、それらをコメントアウトしたので、各出現箇所を次のように置き換えました。

self.firstAsset firstAsset を使用することもできるようですが、「」が頻繁に表示されないことがわかりました。

于 2014-05-06T15:41:10.963 に答える
-1

@synthesizeXcode は明示的な宣言を必要としません。

書いていない場合は、次@synthesizeのことと同じです。

@synthesize manager = _manager;

サンプルコードが古い可能性があります。彼らはすぐにそれを更新します。

次のようなプロパティにアクセスできます。

[self.manager function];

これは Apple が推奨する規則です。私はそれに従います。あなたもそうすることをお勧めします!

于 2013-11-05T08:38:36.607 に答える