宣言されたプロパティのドット表記とメッセージ表記


81

これで、プロパティの「ドット」表記ができました。私は様々な見てきた背中forthsドット表記対メッセージ表記法のメリットについてを。回答を汚さないようにするために、質問ではどちらの方法でも回答しません。

プロパティアクセスのドット表記とメッセージ表記についてどう思いますか?

Objective-Cに焦点を合わせ続けるようにしてください-私が提示する1つのバイアスは、Objective-CがObjective-Cであるため、JavaやJavaScriptのような設定は無効であるということです。

有効な解説は、技術的な問題(操作の順序、キャストの優先順位、パフォーマンスなど)、明確さ(構造とオブジェクトの性質、賛否両論)、簡潔さなどに関するものです。

私はコードの厳格な品質と読みやすさの学校であり、コードの規則と品質が最優先される巨大なプロジェクトに取り組んできました(書き込みは1000回のパラダイムを一度読み取りました)。


14
+1これは素晴らしい質問であり、多くの矛盾する答えが得られます。=)
Dave DeLong

1
ソースコードエディタは、ファイル自体の文字を変更せずに、プログラマの個人的な好みに合わせて調整する必要があります。そうすれば、誰もが好きなものを手に入れることができます。
Arne Evertsson 2010年

回答:


64

動作にドットを使用しないでください。ドットを使用して、ものなどの属性(通常はプロパティとして宣言されている属性)にアクセスまたは設定します。

x = foo.name; // good
foo.age = 42; // good

y = x.retain; // bad

k.release; // compiler should warn, but some don't. Oops.

v.lockFocusIfCanDraw; /// ooh... no. bad bad bad

Objective-Cを初めて使用する場合は、@ propertyとして宣言されているもの以外にはドットを使用しないことをお勧めします。言語を感じたら、正しいと感じることをしてください。

たとえば、私は次のことを完全に自然だと思います。

k = anArray.count;
for (NSView *v in myView.subviews) { ... };

clang static Analyzerは、ドットが特定のパターンにのみ使用されているか、特定の他のパタ​​ーンに使用されていないかを確認できる機能を拡張することが期待できます。


18
うわー、私はあなたがプロパティ以外の何かのためにドット構文を使うことができるとさえ知りませんでした。びっくりした色!(しかし、私は同意します、ドットはプロパティにのみ使用されるべきです)
jbrennan 2009

13
それは正しくありません。ドット表記は、同等のメソッド呼び出しの単純な同義語です。それ以上でもそれ以下でもありません。
bbum 2009

2
ドット表記が@propertyで宣言されたアクセサーに制限されなかったのはなぜだろうか。クラスの作成者は、ドット表記でメソッドを許可する必要がある灰色の領域を解決できたようであり.uppercaseString、クラスがその意図を表現してそれを使用できるように、メソッドを使用するかどうかはそれほど曖昧ではありません。コンパイラによって強制されます。おそらく、ドット表記の現在の実装を必要とする何かが欠けています。

4
に限定された可能性も@propertyありますが、APIの消費者は情報の別のブール次元を学習する必要があり、APIの設計者は、何をすべきか、何をすべきでないかについての議論に溺れる可能性が非常に高くなります@property。Xcodeは@property、コードを完成させるときに、暗黙のメソッドを優先することに注意してください。これは推奨されていますが、強制されていません。
bbum 2010

1
@rodamnそれはそれに答えます。@property言語に不慣れな場合にのみ、宣言されたアクセサでドットを使用することをお勧めします。Objective-Cでのコーディングに自信がついたら、正しいと感じることを実行してください。面白い; 私たちの多くは、ドットの非常に限られた使用に戻ってきました。
bbum 2014年

22

まず、Visual / Real Basicでプログラミングを開始し、次にJavaに移行したので、ドット構文にかなり慣れています。しかし、ようやくObjective-Cに移行して角かっこに慣れ、Objective-C 2.0とそのドット構文の導入を見て、本当に気に入らないことに気づきました。(他の言語の場合は問題ありません。それが彼らの転がり方だからです)。

Objective-Cにはドット構文の3つの主要な牛肉があります。

ビーフ#1:エラーが発生する理由が不明確になります。たとえば、次の行がある場合:

something.frame.origin.x = 42;

次に、somethingはオブジェクトであり、オブジェクトの構造体を式の左辺値として使用できないため、コンパイラエラーが発生します。しかし、私が持っている場合:

something.frame.origin.x = 42;

somethingはNSRectメンバーを持つ構造体自体であり、左辺値として使用できるため、これは問題なくコンパイルされます。

このコードを採用する場合、何であるかを理解するために時間を費やす必要がありsomethingます。構造体ですか?オブジェクトですか?ただし、角かっこ構文を使用すると、はるかに明確になります。

[something setFrame:newFrame];

この場合、がsomethingオブジェクトであるかどうかにかかわらず、あいまいさはまったくありません。あいまいさの導入は私の牛肉#1です。

Beef#2: Cでは、ドット構文は、メソッドを呼び出すのではなく、構造体のメンバーにアクセスするために使用されます。プログラマーは、オブジェクトのメソッドsetFoo:fooメソッドをオーバーライドできますが、それでもsomething.foo。を介してそれらにアクセスできます。私の考えでは、ドット構文を使用した式を見ると、それらはivarへの単純な割り当てであると期待しています。 これは常に当てはまるわけではありません。 配列とテーブルビューを仲介するコントローラーオブジェクトについて考えてみます。を呼び出すとmyController.contentArray = newArray;、古い配列が新しい配列に置き換えられると思います。ただし、元のプログラマーはsetContentArray:、配列を設定するだけでなく、テーブルビューを再ロードするようにオーバーライドした可能性があります。ラインから、その振る舞いの兆候はありません。私が見たら[myController setContentArray:newArray];、そして私は「ああ、メソッド。私はそれが何をしているのかを確実に知るために、このメソッドの定義を見に行く必要がある」と思うでしょう。

ですから、私のビーフ#2の要約は、カスタムコードでドット構文の意味をオーバーライドできるということだと思います。

牛肉#3:見た目が悪いと思います。Objective-Cプログラマーとして、私は完全に括弧で囲むことに慣れているので、美しい括弧の行や行を読んで見て、突然foo.name = newName; foo.size = newSize;などで壊されるのは少し気が散ります。ドット構文(C構造体)が必要なものがあることに気づきましたが、それを使用するのはそれだけです。

もちろん、自分でコードを書いている場合は、使い慣れたものを使用してください。しかし、オープンソースを計画しているコードを書いている場合、または永久に維持することを期待していないものを書いている場合は、ブラケット構文を使用することを強くお勧めします。もちろん、これは私の意見です。

ドット構文に対する最近のブログ投稿:http//weblog.bignerdranch.com/?p = 83

上記の投稿への反論:http//eschatologist.net/blog/?p = 226(ドット構文を支持する元の記事:http//eschatologist.net/blog/?p = 160


5
牛肉#1は私には少し怪しげなようです。構造体にメッセージを送信して、変数が実際には構造体であることを理解する必要がある以上に、それがどのように懸念されるのかわかりません。実際にこれがどのように機能するかを理解している多くの人々がこれに混乱しているのを見ますか?これは、一度台無しにして、左辺値のことを学び、将来的にそれを実行するようなもののように思えます。たとえば、NSNumbersをintのように扱わないようにします。
チャック

2
@Chuckはややエッジケースですが、私はかなりの契約開発を行っています。これには、プロジェクトを継承し、プロジェクトと連携する必要があります。 通常 somethingはオブジェクトですが、元の作成者が構造体を作成した場所(速度、メモリ使用量の削減など)をいくつか見つけたので、コードが作成されない理由を理解するために数分を費やす必要があります。 tコンパイルします。
Dave DeLong

14

私は新しいCocoa / Objective-C開発者であり、私の見解は次のとおりです。

私はObj-C2.0から始めたのに、そしてドット表記がより馴染みのある感じであるにもかかわらず(Javaが私の第一言語です)、メッセージング表記に固執します。これの理由は非常に単純です:私はまだ正確に理解していません彼らが言語にドット表記を追加した理由。私には、それは不必要な「不純な」追加のように思えます。それが言語にどのように役立つかを誰かが説明できれば、私はそれを聞いてうれしいです。

しかし、私はこれを文体の選択だと考えており、他の文体の選択と同じように、一貫性があり読みやすい限り、正しい方法も間違った方法もないと思います(最初のカーリーブレースを同じ行に置くなど)メソッドヘッダーまたは次の行)。


2
+1素晴らしい答え。その背後にある「理由」も知りたいです。おそらくbbumまたはmmalcは答えを知っています...(どちらもで動作します)
Dave DeLong

11

Objective-Cのドット表記は、通常のメッセージパッシングに変換されるシンタックスシュガーであるため、内部では何も変更されず、実行時に違いはありません。ドット表記は、メッセージパッシングよりも絶対に高速ではありません。

この後、少し前文が必要でした。私が見た長所と短所は次のとおりです。

ドット表記の長所と短所

  • 長所

    • 読みやすさ:ドット表記は、ネストされた角かっこマッサージパスよりも読みやすい
    • 属性とプロパティとの相互作用を簡素化します。プロパティにドット表記を使用し、メソッドにメッセージ表記を使用すると、シンサックスレベルで状態と動作を分離できます。
    • 複合代入演算子(1)を使用することができます。
    • @propertyとドット表記を使用すると、コンパイラは多くの作業を行い、プロパティを取得および設定するときに適切なメモリ管理のためのコードを生成できます。これが、ドット表記がApple自体の公式ガイドによって提案されている理由です。
  • 短所

    • ドット表記は、宣言されたものへのアクセスにのみ許可されます @property
    • Objective-Cは標準のC(言語拡張)の上のレイヤーであるため、アクセスされたエンティティがオブジェクトであるか構造体であるかは、ドット表記では実際には明確になりません。多くの場合、構造体のプロパティにアクセスしているように見えます。
    • ドット表記でメソッドを呼び出すと、名前付きパラメーターの可読性の利点が失われます
    • メッセージ表記とドット表記の混合が2つの異なる言語でコーディングしているように見える場合

コード例:

(1)複合演算子の使用コード例:

//Use of compound operator on a property of an object
anObject.var += 1;
//This is not possible with standard message notation
[anObject setVar:[anObject var] + 1];

7

ここでは、言語自体と一致する言語のスタイルを使用することが最善のアドバイスです。ただし、これはオブジェクト指向システムで関数型コードを記述する場合ではなく(またはその逆)、ドット表記はObjective-C2.0の構文の一部です。

どのシステムも悪用される可能性があります。すべてのCベースの言語にプリプロセッサが存在することは、非常に奇妙なことを行うのに十分です。ちょうど見難読Cコンテストあなたはそれを得ることができますどのように奇妙な正確に確認する必要がある場合。それは、プリプロセッサが自動的に不良であり、決して使用してはならないことを意味しますか?

インターフェイスでそのように定義されているプロパティにアクセスするためにドット構文を使用すると、悪用される可能性があります。ポテンシアにおける虐待の存在は、必ずしもそれに反対する議論であるべきではありません。

プロパティへのアクセスには副作用がある場合があります。これは、そのプロパティを取得するために使用される構文と直交しています。CoreData、委任、動的プロパティ(first + last = full)はすべて、必然的に内部で何らかの作業を行います。しかし、それは「インスタンス変数」とオブジェクトの「プロパティ」を混同することになります。特にプロパティを計算できる場合(たとえば、文字列の長さ)、プロパティを必ずしもそのまま保存する必要がある理由はありません。したがって、foo.fullNameを使用するか[foo fullName]を使用するかにかかわらず、動的評価は引き続き行われます。

最後に、プロパティの動作(左辺値として使用される場合)は、コピーが作成されるか保持されるかなど、オブジェクト自体によって定義されます。これにより、メソッドを再実装する必要がなく、後で(プロパティ定義自体で)動作を簡単に変更できます。これにより、アプローチの柔軟性が高まり、結果として発生する(実装)エラーが少なくなる可能性があります。間違った方法(つまり、保持する代わりにコピー)を選択する可能性はまだありますが、それは実装の問題ではなくアーキテクチャの問題です。

最終的に、それは「構造体のように見えるか」という質問に要約されます。これはおそらくこれまでの議論の主な差別化要因です。構造体がある場合は、オブジェクトがある場合とは動作が異なります。しかし、それは常に真実です。構造体にメッセージを送信することはできません。また、それがスタックベースか参照/ mallocベースかを知る必要があります。使用法が異なるメンタルモデルがすでにあります([[CGRect alloc] init]またはstructCGRect?)。それらは振る舞いに関して統一されたことがありません。それぞれの場合に何を扱っているかを知る必要があります。オブジェクトのプロパティ表示を追加しても、データ型が何であるかを知っているプログラマーを混乱させる可能性はほとんどありません。そうでない場合は、より大きな問題が発生します。

一貫性については; (Objective-)Cはそれ自体の中で一貫性がありません。=は、ソースコード内の字句位置に基づいて、割り当てと同等性の両方に使用されます。*はポインタと乗算に使用されます。BOOLは、YESとNOがそれぞれ1と0であるにもかかわらず、バイト(または他の整数値)ではなく文字です。一貫性や純粋さは、言語が設計された目的ではありません。それは物事を成し遂げることについてでした。

したがって、使用したくない場合は使用しないでください。別の方法でそれを実行します。使いたくて理解できれば、使っても大丈夫です。他の言語は、ジェネリックデータ構造(マップ/構造体)とオブジェクトタイプ(プロパティ付き)の概念を扱い、一方が単なるデータ構造でもう一方がリッチオブジェクトであるにもかかわらず、両方に同じ構文を使用することがよくあります。Objective-Cのプログラマーは、好みのプログラミングではない場合でも、すべてのスタイルのプログラミングを処理できる同等の能力を備えている必要があります。


6

プロパティに使用しているのは

for ( Person *person in group.people){ ... }

より少し読みやすいです

for ( Person *person in [group  people]){ ... }

2番目のケースでは、脳をメッセージ送信モードにすることで読みやすさが損なわれますが、最初のケースでは、グループオブジェクトのpeopleプロパティにアクセスしていることが明らかです。

たとえば、コレクションを変更するときにも使用します。

[group.people addObject:another_person];

より少し読みやすいです

[[group people] addObject:another_person];

この場合、2つのメッセージをチェーンするのではなく、オブジェクトを配列に追加するアクションに重点を置く必要があります。


5

私は主にObjective-C2.0の時代に育ちましたが、ドット表記が好きです。私にとっては、余分な括弧を付ける代わりに、コードを単純化することができます。ドットを使用するだけです。

また、ドット構文は、メッセージを送信するだけでなく、オブジェクトのプロパティにアクセスしているように感じるので気に入っています(もちろん、ドット構文は実際にはメッセージ送信に変換されますが、外観のためです。 、ドットの感じが異なります)。古い構文で「ゲッターを呼び出す」のではなく、オブジェクトから何か有用なものを直接取得しているように感じます。

これに関する議論のいくつかは、「しかし、私たちはすでにドット構文を持っています、そしてそれはstructs!」に関するものです。そしてそれは本当です。しかし(そして繰り返しますが、これは単なる心理的です)基本的に私には同じように感じます。dot-syntaxを使用してオブジェクトのプロパティにアクセスすることは、構造体のメンバーにアクセスすることと同じように感じます。これは、多かれ少なかれ意図された効果です(私の意見では)。

****編集:bbumが指摘したように、オブジェクトの任意のメソッドを呼び出すためにdot-syntaxを使用することもできます(私はこれに気づいていませんでした)。したがって、dot-syntaxに関する私の意見は、オブジェクトのプロパティを処理するためだけのものであり、日常のメッセージ送信ではありません**


3

私はメッセージング構文を非常に好みます...しかしそれが私が学んだことだからです。私のクラスの多くとObjective-C1.0スタイルにないものを考えると、それらを混ぜたくありません。ドット構文を使わないのは「慣れている」以外に本当の理由はありません...これを除いて、これは私を狂気に駆り立てます

[myInstance.methodThatReturnsAnObject sendAMessageToIt]

理由はわかりませんが、理由もなく、本当に腹立たしいです。私はただやっていると思います

[[myInstance methodThatReturnsAnObject] sendAMessageToIt]

より読みやすくなります。しかし、それぞれに!


3
私は時々これを行いますが、それは私がプロパティにアクセスしている場合に限ります。例:[self.title lowercaseString]または何か。しかし、構文を組み合わせるのが面倒な理由をスタイル的に理解できます。私がそれを行う唯一の理由は、プロパティとは何か、オブジェクトを返すメソッドとは何かをまっすぐに保つことです(プロパティは本当にそれだけだと知っていますが、うまくいけば私が言っていることを理解できます)。
jbrennan 2009

3

正直なところ、それはスタイルの問題だと思います。私は個人的にドット構文に反対しています(特に、変数の読み取り/書き込みだけでなく、メソッド呼び出しに使用できることがわかった後)。ただし、使用する場合は、変数へのアクセスと変更以外の目的に使用しないことを強くお勧めします。


3

オブジェクト指向プログラミングの主な利点の1つは、オブジェクトの内部状態に直接アクセスできないことです。

ドット構文は、状態が直接アクセスされているかのように見えるようにする試みのように思えます。しかし実際には、これは動作-fooおよび-setFoo:に対する単なる構文糖衣です。私自身、スペードをスペードと呼ぶのが好きです。ドット構文は、コードがより簡潔になる程度に読みやすさを向上させますが、実際に-fooおよび-setFoo:を呼び出していることを覚えていない場合、問題が発生する可能性があるため、理解には役立ちません。

合成されたアクセサーは、状態に直接アクセスするオブジェクトを簡単に記述できるようにする試みのように思えます。私の信念は、これはオブジェクト指向プログラミングが回避するために作成された種類のプログラム設計を正確に奨励するということです。

結局のところ、私はむしろドット構文を望み、プロパティは導入されたことがありませんでした。私は以前、ObjCがSmalltalkのようにするためのCのいくつかのクリーンな拡張機能であることを人々に伝えることができましたが、それはもはや真実ではないと思います。


2

私の意見では、ドット構文により、Objective-CはSmalltalk風ではなくなります。コードを単純に見せることができますが、あいまいさが増します。それはstructunion、またはオブジェクト?


2

多くの人が「プロパティ」と「インスタンス変数」を混同しているようです。プロパティのポイントは、オブジェクトの内部を知らなくてもオブジェクトを変更できるようにすることだと思います。インスタンス変数は、ほとんどの場合、プロパティの「実装」(これは「インターフェース」)ですが、常にではありません。プロパティがivarに対応しない場合があり、代わりに戻り値を計算します。急いで'。

そのため、「ドット構文は、変数にアクセスしていると思わせて混乱させる」という考えは間違っていると思います。ドットまたは括弧、内部についての仮定をするべきではありません:それはプロパティであり、ivarではありません。


ちなみに、Objective-Cオブジェクト参照は直接のC構造体変数ではなく、「構造体へのポインタ」に似ているため、ドット構文はメンバーに直接アクセスする意味がありません。->その役割を果たすのは矢印演算子です(もちろん、ivarがアクセス制限されていない場合はいつでも)。
ニコラスミアリ2015年

1

私の頭の中でobject.instanceVarオブジェクトに属するinstanceVarであるため、ドット表記ではなくメッセージングに切り替える可能性があると思います。私にとっては、メソッド呼び出しのようには見えないので、何かが起こっている可能性があります。アクセサでオンにし、instanceVarself.instanceVarのどちらを使用するかによって、単純な暗黙的なものと明示的なものよりもはるかに大きな違いが生じる可能性があります。ちょうど私の2¢。


1

ドット表記は、メッセージを構造体のメンバーへのアクセスのように見せようとしますが、そうではありません。場合によっては正常に動作する可能性があります。しかし、すぐに誰かがこのようなものを思い付くでしょう:

NSView *myView = ...;
myView.frame.size.width = newWidth;

うまく見えます。しかし、そうではありません。それはと同じです

[myView frame].size.width = newWidth;

これは機能しません。コンパイラーは最初のものを受け入れますが、当然のことながら2番目のものは受け入れません。そして、最初にエラーや警告が表示されたとしても、これは混乱を招きます。


1

私を怠惰と呼んでください、しかし私が単一の「。」をタイプしなければならなかったならば。対2 []毎回同じ結果を得るには、1つをお勧めします。私は冗長な言語が嫌いです。Lispの()は私を狂わせた。数学などのエレガントな言語は簡潔で効果的ですが、他のすべての言語は不十分です。


1
問題は、数学は簡潔で効果的ですが、正規言語ではないため、解析してコンパイルできないことです。たとえば、数学関数では、括弧を付けて記述するのが一般的であることに注意してください。括弧を付けないと従うのがはるかに困難になるためです。
jbrennan 2010年

1

ドット表記を使用する(可能な場合はいつでも)

何らかの値を返すインスタンスメソッド

ドット表記は使用しないでください

voidを返すインスタンスメソッド、initメソッド、またはClassメソッド。

そして私の個人的なお気に入りの例外

NSMutableArray * array = @[].mutableCopy;

0

私は個人的にコードでドット表記をまったく使用していません。必要な場合にのみ、CoreDataKVCバインディング式で使用します。

私のコードでそれらを使用しない理由は、ドット表記がセッターのセマンティクスを隠すためです。ドット表記でプロパティを設定すると、セッターのセマンティクス(割り当て/保持/コピー)に関係なく、常に割り当てのように見えます。メッセージ表記を使用すると、受信オブジェクトがセッターで何が発生するかを制御できることがわかり、それらの影響を考慮する必要があるという事実が強調されます。

確かにもう少しコンパクトで読みやすく、隠されたセマンティクスがないため、KVC準拠または宣言されたプロパティの値を取得するときにドット表記を使用するかどうかをまだ検討しています。現在、一貫性を保つためにメッセージ表記を使用しています。


1
まだ隠されたことが起こっているかもしれません。ゲッターは、インスタンス変数を返すだけでなく、他のこともできます。宣言されたプロパティであっても、ゲッターを合成する必要はありません。そうしないと、サブクラスでオーバーライドされる可能性があります。
2010

-1

OK、Objective-Cのドット表記は確かに奇妙に見えます。しかし、それなしではまだ次のことはできません。

int width = self.frame.size.width;

正常に動作しますが:

int height = [[[self frame] size] height];

「ポインタ型に変換できません」と表示されます。ただし、コードの外観をメッセージ表記と一致させたいと思っています。


5
-frameは、Objective-CオブジェクトではなくC構造体であるNSRectを返します。そのため、2番目の例ではコンパイラエラーが発生します。次のようになります。intheight= [self frame] .size.height;

1
同意しました。しかし、括弧の後のドットはひどいように見えます!私は通常、最初にローカル変数にrectを格納します。
ニコラスミアリ2012年

-2

これは素晴らしい質問であり、私はこれに対する多くの異なる答えを見ています。多くの人がトピックに触れていますが、私はこれに別の角度から答えようとします(暗黙のうちにそれを行った人もいます):

'dot'表記を使用する場合、メソッドのターゲットの解決はコンパイル時に行われます。メッセージパッシングを使用する場合、ターゲットの解決は実行時の実行に延期されます。コンパイル時にターゲットが解決されると、実行時にターゲットを解決するためにいくつかのオーバーヘッドが含まれるため、実行が速くなります。(時差がそれほど重要になるわけではありません)。オブジェクトのインターフェイスでプロパティをすでに定義しているので、プロパティのターゲットの解像度を実行時に異ならせる意味はありません。したがって、ドット表記は、プロパティにアクセスするために使用する必要がある表記です。


ObjectiveCでは、セレクターが実行時に評価、解決、呼び出されることをご存知ですか?したがって、ドット表記は古いブラケットスタイルの純粋な同義語です。技術的な違いは一切ありません。あなたの速度の仮定は明らかに間違っています-それを試して、Instrumentsを使用して自分自身を見てください。
2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.