9

私は Obj-c と Cocoa で数年の経験がありますが、Obj-C 2.0 などの進歩に戻ってきたばかりです。

私は最新のランタイムとプロパティの宣言などに頭を悩ませようとしています。私を少し混乱させることの 1 つは、最新のランタイムで iVar を暗黙的に作成できることです。そしてもちろん、これはコード内で常に self.property を使用して値にアクセスする必要があることを意味します。

ただし、init* および dealloc (GC を使用していないと仮定) メソッドでは、(現在のランタイムで) iVar を直接使用する必要があります。

質問は次のとおりです。

  1. init* でプロパティ アクセサーを使用し、最新のランタイムで dealloc を使用する必要がありますか?

  2. もしそうなら、なぜこれは違うのですか?コンパイラが iVar を認識できないからですか?

  3. アクセサーをオーバーライドする必要がある場合、実行時に定義される iVar に引き続きアクセスできますか? または、ランタイムが使用する実際の iVar を定義する必要がありますか?

  4. 繰り返しますが、合成された iVar にアクセスできる場合、 init* および dealloc メソッドに対してこれを続けられないのはなぜですか?

ドキュメントを何度か読みましたが、これらすべてについて少し曖昧に思えたので、どのようにコーディングを続けたいかを決定するために、よく理解していることを確認したいと思います。

私の質問が明確であることを願っています。


テストの簡単な要約:

  1. レガシーでivarを宣言しないと、コンパイラは完全に不満です

  2. #ifndef __OBJC2__レガシーコンパイラで ivarを使用する場合は満足であり、 ivar を直接およびプロパティとして使用できます

  3. 最新のランタイムでは、ivar を未定義のままにして、プロパティとしてアクセスできます

  4. 最新のランタイムでは、宣言なしで ivar に直接アクセスしようとすると、コンパイル中にエラーが発生します

  5. @privateもちろん、ivar の宣言により、レガシーとモダンの両方で ivar に直接アクセスできます。

今のところ、前に進むための明確な方法を本当に提供していませんか?

4

5 に答える 5

1

インスタンス変数自体は最新のランタイムでしか合成できないため (32 ビットまたは Leopard より前の環境では @interface で宣言する必要があります)、ivar も宣言するのが最も安全で移植性が高くなります。

  • init* でプロパティ アクセサーを使用し、最新のランタイムで dealloc を使用する必要がありますか?

私の経験則では、 は「おそらく」、-init*は「通常はそうではない」です-dealloc

オブジェクトを初期化するときは、ivar の値を適切にコピー/保持する必要があります。プロパティのセッターに、初期化に適さない副作用がある場合を除き、プロパティが提供する抽象化を確実に再利用してください。

オブジェクトの割り当てを解除するとき、ivar オブジェクトを解放したいが、新しいオブジェクトを保存したくない。これを行う簡単な方法は、プロパティを nil( myObject.myIvar = nil) に設定することです。これは基本的に を呼び出します[myObject setMyIvar:nil]。nil へのメッセージは無視されるため、危険はありません。ただし、[myIvar release] の場合はやり過ぎです。通常はこれだけで十分です。一般に、割り当て解除が変数の設定とは異なる動作をする必要がある状況では、プロパティ (または直接、セッター) を使用しないでください。

init/dealloc でプロパティ アクセサーを使用することに対する eJames の主張はまったく理解できますが、反対に、プロパティの動作を変更した場合 (たとえば、保持からコピーに変更するか、保持せずに単に割り当てる)、それを使用しないでください。 init で、またはその逆の場合、動作も同期しなくなる可能性があります。ivar の初期化と変更が同じように動作する必要がある場合は、両方にプロパティ アクセサーを使用します。

  • もしそうなら、なぜこれは違うのですか?コンパイラがivarを認識できないからですか?

最新のランタイムは、クラスのサイズとレイアウトをよりインテリジェントに処理するため、サブクラスを再コンパイルすることなく ivar のレイアウトを変更できます。また、対応するプロパティの名前とタイプから、必要な ivar の名前とタイプを推測することもできます。Objective-C 2.0 ランタイム プログラミング ガイドにはより多くの情報がありますが、ここでも、詳細がどの程度詳細に説明されているかわかりません。

  • アクセサーをオーバーライドする必要がある場合、実行時に定義される iVar に引き続きアクセスできますか? または、ランタイムが使用する実際の iVar を定義する必要がありますか?

私はこれをテストしていませんが、実際には作成する必要があるため、コードで名前付き ivar にアクセスできると思います。コンパイラが文句を言うかどうかはわかりませんが、文句を言わずにivarを合成できるので、合成されたivarを知って名前で参照できるほど賢いと思います。

  • 繰り返しますが、合成された iVar にアクセスできる場合、init* および dealloc メソッドに対してこれを続けられないのはなぜですか?

インスタンスが割り当てられた後は、いつでもプロパティや ivar にアクセスできるはずです。

于 2009-06-17T15:55:00.690 に答える
0

私は Obj-C に比較的慣れていませんが (プログラミングには慣れていません)、このトピックにも混乱しています。

私が心配しているのは、プロパティの代わりに iVar を誤って使用することが比較的簡単にできるように思われることです。たとえば、次のように記述します。

myProp = someObject;

それ以外の

self.myProp = someObject;

確かにこれは「ユーザー」エラーですが、一部のコードでは偶発的に実行するのは非常に簡単であり、保持またはアトミック プロパティの場合、おそらく問題につながる可能性があります。

理想的には、 iVarを生成するときに、ランタイムがプロパティ名に何らかのパターンを適用できるようにしたいと考えています。たとえば、常に先頭に「_」を付けます。

現時点では、実際にはこれを手動で行っています。ivar を明示的に宣言し、意図的にプロパティとは異なる名前を付けています。古いスタイルの「m」プレフィックスを使用しているため、プロパティが「myProp」の場合、iVar は「mMyProp」になります。次に @synthesize myProp = mMyProp を使用して 2 つを関連付けます。

これは確かに少しぎこちなく、余分な入力が少しありますが、コード内でもう少し明確にあいまいさを解消できるようにすることには価値があるように思えます。もちろん、まだ間違って mMyProp = someObject と入力することはできますが、'm' プレフィックスがエラーを警告してくれることを願っています。

プロパティを宣言するだけでコンパイラ/ランタイムに残りを任せれば、もっと気分が良くなるのですが、コードがたくさんあると、手動のルールに従わなければならない場合、そのように間違いを犯すだろうと本能的に教えてくれます。 init/dealloc 用。

もちろん、私が間違っている可能性があることは他にもたくさんあります...

于 2010-03-04T00:51:49.060 に答える
0

私は同じ問題に直面しています。合成されたインスタンス変数にアクセスできないことを回避する方法は次のとおりです。

公開ヘッダー

@interface MyObject:NSObject {
}
@property (retain) id instanceVar;
@property (retain) id customizedVar;
@end

プライベート ヘッダー/実装

@interface MyObject()
@property (retain) id storedCustomizedVar;
@end

@implementation MyObject
@synthesize instanceVar, storedCustomizedVar;
@dynamic customizedVar;

- customizedVar {
  if(!self.storedCustomizedVar) {
    id newCustomizedVar;
    //... do something
    self.storedCustomizedVar= newCustomizedVar;
  }
  return self.storedCustomizedVar;
}

- (void) setCustomizedVar:aVar {
  self.storedCustomizedVar=aVar;
}

@end

それほど洗練されたものではありませんが、少なくともパブリック ヘッダー ファイルをきれいに保つことができます。

KVO を使用する場合は、customizedVar を storedCustomizedVar の依存キーとして定義する必要があります。

于 2009-07-26T15:26:41.350 に答える