web-dev-qa-db-ja.com

Objective Cでプロパティ名に下線を付ける

私は以前、変数名の下線、おそらく私の大学からの持ち越しを避けてきましたJava日。したがって、Objective Cでプロパティを定義するとき、これは当然のことです。

// In the header
@interface Whatever
{
    NSString *myStringProperty
}

@property (nonatomic, copy) NSString *myStringProperty;

// In the implementation
@synthesize myStringProperty;

しかし、ほとんどすべての例で、次のように行われます

// In the header
@interface Whatever
{
    NSString *_myStringProperty
}

@property (nonatomic, copy) NSString *myStringProperty;

// In the implementation
@synthesize myStringProperty = _myStringProperty;

アンダースコアへの嫌悪感を乗り越えなければならないのは、それが行われるべき1つの方法だからです。このスタイルが好まれるのには十分な理由がありますか?

pdate:現在の自動プロパティ合成では、@ synthesizeを省略でき、結果は使用した場合と同じです

@synthesize myStringProperty = _myStringProperty;

これは明らかにAppleの好みを示している。私はそれ以来、心配するのをやめ、アンダースコアを愛することを学びました。

55
Michael Behan

常にアンダースコアを使用します。ローカル変数とインスタンス変数を明確に区別します。また、次の状況ではコンパイラの警告も回避されます。

@interface MyClass
{
    NSString *name
}

@property (nonatomic, copy) NSString *name;

- (id) initWithName:(NSString *) name;
@end

@implementation MyClass

@synthesize name;

// The following method will result in a compiler warning
// (parameter name same as ivar name)
- (id) initWithName:(NSString *) name {
   if (self = [super init]) {
      self.name = name;
   }

   return self;
}

@end

[〜#〜]編集[〜#〜]

反対投票に耐え、コメントを読んだ後、私の主張を述べさせてください。

アップルでは、​​ivarはプロパティと同じ名前にすることをお勧めしています。 Appleは、プロパティが小文字で始まることも推奨しています。そしてAppleは、ローカル変数が小文字で始まることも推奨しています。

これで問題が発生しました。コードを読んで変数が使用されているのを見ると、この変数がivarとローカル変数のどちらであるかを命名規則で判別できないためです。それは最悪だ。解決策は、ivarとローカル変数に異なる命名規則を設けることです。それは単なる常識です。

この命名規則を実装する方法は重要ではありません。本当に必要な場合は、単にivar名に "_WOOHAHA"を追加できます。私は気にしません(しかし、他の人はそうするでしょう)。問題は、自分が何をしているのかを知っている人々が、ivarの「アンダースコアプレフィックス」を使用することに決めたことです。私見、自分の会社が他のことを勧めていても、彼らは正しい決定をしました。 (私が話している開発者は、いくつかのメジャーAppleフレームワークと.NET Frameworkクラスを書いている人たちです)

結局、コードの品質は、それを説教する人々が従わない愚かなルールに従うよりも重要です。


これまでに示したコードについての別の注意:文字列のプロパティにはretainを使用しないでください。代わりにcopyを使用してください。

プロパティのコピー/保持の詳細については、以下を参照してください。

NSStringプロパティ:コピーまたは保持?

47

_が前に付いたインスタンス変数の命名規則は、2012-02-16の改訂後、その理由により、Appleによって明確に記述されています。

インスタンス変数の名前が、格納されている属性を簡潔に説明していることを確認してください。通常、インスタンス変数に直接アクセスするのではなく、代わりにアクセサメソッドを使用する必要があります(initおよびdeallocメソッドでインスタンス変数に直接アクセスします)。これを通知するには、インスタンス変数名の前にアンダースコア(_)を付けます。次に例を示します。

@implementation MyClass {
    BOOL _showsTitle;
}

宣言したプロパティを使用してインスタンス変数を合成する場合は、@ synthesizeステートメントでインスタンス変数の名前を指定します。

@implementation MyClass
@synthesize showsTitle=_showsTitle;

https://developer.Apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html#//Apple_ref/doc/uid/20001284-BAJGIIJE

ITunes U、スタンフォード大学のPaul Hegartyによる2011年秋のiPhone App Development CS193p Fallでの講義も、この慣例を説明しています。

http://iTunes.Apple.com/iTunes-u/ipad-iphone-application-development/id473757255

私はこの質問がかなり前に尋ねられたことを知っていますが、私自身も同じ質問があり、私の発見を共有したいと思いました。

29
Taka

現在推奨されているObjective-C 2.0のプラクティスは、プロパティとしてivarに同じ名前を使用することです。必要に応じて、@ property宣言で別のivarを割り当てることができますが、デフォルトでは、プロパティの合成アクセサーはプロパティと同じ名前のivarにアクセスするため、ユーザーが期待するパターンを示しています。

プロパティにアクセスするためにオブジェクトが自分自身にメッセージを送信する必要があるため、プロパティにアクセスしているとき、またはバッキングivarに直接アクセスしているときは混乱しにくいですが、プロパティへの2.0ドットアクセスを使用すると、より可能です。標準のメッセージ受け渡し構文を使用すると、意図がより明確になります(IMO)。

@interface Foo : NSObject {
     NSNumber *bar;
} 
@property(readwrite, retain) NSNumber * bar
@end

@implementation Foo 
@synthesize bar;

-(void) baz {
   NSNumber *numberOne = [NSNumber numberWithInt: 1];   
   //Both set the value of bar through either the your custom or the synthesized setter method
   [self setBar:numberOne];  
   self.bar = numberOne; 

   //Both get the value of bar through your synthesized or your custom accessor method
   NSNumber *fooBar = [self bar];
   fooBar = self.bar;

   //Both manipulate the bar ivar directly
   bar = numberOne;
   fooBar = bar;
}
@end 
18
mlwelles

Appleは、アンダースコアで始まるセレクタを独自の「プライベート」メソッド用に予約しており、これにはプロパティが含まれます。私は彼らがivar名のために_を予約するとは思わない。

個人的には、アンダースコアを使用してあらゆる種類の変数名を開始することは避けます。それは不透明な慣習です。他の誰かがローカル変数にアンダースコアを使用し、インスタンス変数にアンダースコアを使用しない場合はどうなりますか?同じ名前でローカルが定義されているメソッドで誤ってアンダースコアを省略した場合はどうなりますか?

ローカル名をivar名とは異なるものにした方がはるかに優れています。たとえば、セッターでは、newNameまたはneWValueを使用できます。

6
JeremyP

それは純粋にスタイルの問題です。

下線付きのivarスタイルを使用している例はわかりません。公式のAppleの例(例 CryptoExercise )は、ivarの前に_を付けません。

3
kennytm

コアデータを使用する新しいナビゲーションプロジェクトは、デフォルトでtrailingアンダースコアを使用し、変数をプライベートにすることを指摘します。

@interface MyTestAppDelegate : NSObject <UIApplicationDelegate> {

    UIWindow *window;
    UINavigationController *navigationController;

@private
    NSManagedObjectContext *managedObjectContext_;
    NSManagedObjectModel *managedObjectModel_;
    NSPersistentStoreCoordinator *persistentStoreCoordinator_;
}

@interface RootViewController : UITableViewController <NSFetchedResultsControllerDelegate> {

@private
    NSFetchedResultsController *fetchedResultsController_;
    NSManagedObjectContext *managedObjectContext_;
}
2
jon

ランタイムのKVC部分は、オブジェクトでvalueForKey:を使用するときに、その変数を取得するためのメッセージを見つけることができない場合、名前または_name ivarを予期します。参照 http://developer.Apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/Concepts/SearchImplementation.html

ランタイムが_nameおよびApple=のドキュメントで最初に_nameについて言及していることに悩まされている場合、これには十分な理由がある可能性があります。いくつかのSDKクラスを見てみましょう。UINavigationBar.hこのクラスには下線が付いていますすべてのivarsの前で、UIViewも...リストは続きます。まあ、それは、おそらく新しいfangled iOS SDKとそのようなOLE NS *クラスがそのように機能しないことです...間違っています。アンダースコアを使用しています同様にヘッダーファイルで。

Appleは、プライベートAPIメッセージとivarでアンダースコアを使用します。特にランタイムがこれをいわゆる「命名規則」に変えて変数検索パスにハードコーディングする必要があるときに、彼らの例がなぜこの動作をプッシュしないのか理解できません。ある程度の一貫性があるといいですね。

KVCに準拠するには、厳密な命名規則に従う必要があります。上記のリンクは、ランタイムのこの便利な機能を使用するためにこれに準拠するのに役立ちます。

1
Brent Priddy