真の力を得るためには、闇を知る必要があります。暗黒面を乗り越え、真のObjective-C使いへの道を開きましょう。
恐れから目を背けた者に、怒りや憎しみを乗り越えることはできぬのじゃ・・・(緑色の偉い人)
メソッド宣言時、前方の空白は書かない
ダークサイ度:☆☆☆☆☆
型破りなスタイルですが、特に問題はありません。
// Before
- (void)yoda {}
// After
-(void)yoda {}
入力補完は問題なく効きますし、文字数やタイプ数も減りますので、ダークサイ度は星ゼロとしました。
ちなみに私は自作メソッドとオーバライド・メソッドとの区別を付ける際にもこのスタイルを活用しています。
id型を活用する
ダークサイ度:★★☆☆☆
id str = @"a,b,c", sep = @",";
id ary = [str componentsSeparatedByString:sep];
if ([ary count])
NSLog([ary firstObject]);
for (id string in ary)
NSLog(@"%ld", [string length]);
上記のコードはXcode環境であれば問題なくコンパイル出来ますし、入力補完も効きます。 これは型推論ではないのですが、id型に対するメッセージ呼び出しは型チェックや名前解決が緩くなるため、このような記述が可能です。Objective-Cをより軽量言語的に使いたい場合は有効なテクニックだと思います。
デバッグ時に利用する程度であればそれほど問題はないイディオムだと感じていますが、戻り値型の変更を行った際にコンパイラが型の不一致を検知できなくなるデメリットがあります。実運用時の多用には注意が必要です。ダークサイ度は星2つとしました。
上記サンプルのような仕様変更の少ないライブラリの戻り値で利用する程度であれば、ほとんど問題にはならないでしょう。ただし、id型はプロパティアクセスが行えない点が難点です。Objective-C 3.0以降でid型に対する型推論が出来る様になることを期待します。
メッセージも可能な限りプロパティアクセスする
ダークサイ度:★★★☆☆
// Before
[[NSObject alloc] init];
[[[NSUserDefaults standardUserDefaults] stringForKey:@""] copy];
// After
[NSObject.alloc init]; // initは引数追加時を考慮し、あえてプロパティアクセスを行わない
[NSUserDefaults.standardUserDefaults stringForKey:@""].copy;
ただし、メソッドに対するプロパティアクセスはIDEの補完が効きません(Xcode 7では「NSObject.al」と入力してもallocメソッドをサジェストしてくれない)。そのためダークサイ度は★三つとしました。現場のコーディング規約として加えるにはかなりの注意と覚悟が必要です。
もっとも、allocやcopy等の定型文でのみ例外的に利用する程度であれば、かなり効果的なスタイルとなります。
なお、Xcode 8の最新コンパイラではクラス・メソッドに対してもプロパティ宣言が可能になりました。将来的にFoundation Kit側のallocやcopyについても、インスタンス・メソッド同様にプロパティ化が行われるようになるのではないかと思われます。
標準クラスの別名を作る
ダークサイ度:☆☆☆☆☆
typedefでよく使う標準クラスの別名を作ります。これによって「NS」プレフィックスやポインタを記述する必要も無くなります。
// Before
-(NSString *)substr:(NSString *)str loc:(NSNumber *)loc len:(NSInteger)len {
NSString *sub = [str substringWithRange:NSMakeRange(loc.integerValue, len)];
return (NSString *)sub;
}
// After
typedef NSString* String;
typedef NSNumber* Number;
typedef NSInteger Int;
-(String)substr:(String)str loc:(Number)loc len:(Int)len {
String sub = [str substringWithRange:NSMakeRange(loc.integerValue, len)];
return (String)sub;
}
見た目がJavaっぽくなりました。外部ライブラリとの名前衝突が懸念されますが、そもそも外部ライブラリではプレフィックスの利用が推奨されているため、ほとんど問題にはならないでしょう。ダークサイ度は星ゼロとしました。
アスタリスクが無くなることで、値型とポインタ型の区別が曖昧になる恐れがありますが、NSString/Stringのような頻繁に目にするクラス名に関してはそれほど問題にはならないでしょう。むしろ頻繁に目にするからこそシンプルに書きたいところです。
インデントを空白二つに設定する
ダークサイ度:★☆☆☆☆
インデントを空白二つに設定することでコードがコンパクトになります。 Objective-Cの標準ライブラリはメッセージ名が長い物が多く、テキストエディタの横幅をどうしても広く使ってしまうため、2スペースインデントはかなり効果的な対応策となります。
ただし、インデントに空白を2つ使うスタイルは慣れの問題もあるため、星一つとしました。複数人で開発を行う際には注意しましょう。
2スペース派と4スペース派で意見が別れる場合はインデントに空白を3つ使うスタイルもオススメですので、検討してみてください(3スペース・インデントのススメ)。
ポインタの空白を省略する
ダークサイ度:★★☆☆☆
// Before
-(NSString *)replace:(NSString *)trg replacement:(NSString *)rep {
return (NSString *)replace(trg, rep);
}
// After
-(NSString*)replace:(NSString*)trg replacement:(NSString*)rep {
return (NSString*)replace(trg, rep);
}
かなりの文字数を削減出来ます。
ポインタ型記法はあまりメジャーな書き方ではありませんが、メッセージ式にのみ限定して用いる程度であればそれほど問題はないように思います。
ポインタ型記法のススメ 〜int *p VS int* p 空白をどちらに挿入するか〜
ただし、Xcodeの入力補完を行う際には、自動的に空白ありでの補完・変換が行われてしまいます。記法の一貫性が失われてしまう問題もあるため、慎重に利用しましょう。
ダークサイ度は星2つとしました。
なお、標準ライブラリのデリゲートを入力補完する際も、同様に空白ありでの補完が行われますが、これは自作のメッセージとライブラリ側のデリゲートを区別する手段にもなります。中にはこれをメリットと見る者もいるでしょう。overrideキーワードがないObjective-Cならではの工夫にもなります。
ピンバック: ライトサイド Objective-C コーディング規約 | MaryCore
ピンバック: メソッドとプロパティの境界が曖昧【Objective-Cの良い所 その3】 | MaryCore