1. ホーム
  2. objective-c

[解決済み] どのような場合に@synthesizeを明示的に使用する必要がありますか?

2022-02-06 17:29:09

質問

私の知る限り、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 を明示的に追加してください。

どのように解決するのですか?

たくさんの答えがある一方で、大きな混乱もあります。私はいくつかの順序を置く(または混乱を増加させる、我々は見てみましょう...)しようと思います。

  1. Xcodeの話はもうやめましょう。Xcodeは IDE .clangは コンパイラ . 今回取り上げるこの機能は プロパティの自動合成 で、これは clang がサポートする Objective-C 言語拡張 Xcode が使用するデフォルトのコンパイラです。
    もしXcodeでgccに切り替えたら、この機能の恩恵は受けられません(Xcodeのバージョンに関係なく)。同じように、テキストエディタを使って、コマンドラインからclangを使ってコンパイルすれば、恩恵を受けることができます。

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

    @synthesize propertyName = _propertyName
    
    

    ただし、いくつかの例外は存在します。

    • カスタムゲッターとカスタムセッターを持つ readwrite プロパティ。

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

    • カスタムゲッターを持つ読み取り専用プロパティ

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

    • ダイナミック

      を使用する場合 @dynamic propertyName を使用すると、プロパティが自動的に合成されなくなります (かなり明白ですが、これは @dynamic@synthesize は相互に排他的である)

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

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

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

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

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

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

注意すべきは、プロパティを合成すると、自動的にバックのivarも合成されることです。したがって、プロパティの合成が欠落している場合、明示的に宣言しない限り、ivarも欠落してしまいます。

最後の3つのケースを除いて、一般的な考え方は、プロパティに関するすべての情報を手動で指定する場合(すべてのアクセッサメソッドを実装するか、または @dynamic コンパイラは、あなたがそのプロパティを完全に制御したいのだと判断し、そのプロパティの自動合成を無効化します。

上に挙げたケース以外では、明示的な @synthesize は、別のivar名を指定する場合です。しかし、規約は重要なので、私のアドバイスは、常にデフォルトの命名を使用することです。