訳者補記1 Xcode 4.4のリリース時にObjective-Cに追加された機能

この補記では、Xcode 4.4のリリース時にObjective-Cに追加された機能を紹介します(Modern Objective-Cと呼ばれます)。これらの機能により、コードがより簡素に記述できるようになります。

デフォルト@synthesize

実装がない@propertyを合成(自動生成)するためには@synthesizeが必要でしたが、@synthesizeがなくても合成されるようになりました。

// Appliance.h
@interface Appliance : NSObject

@property (copy, nonatomic) NSString *productName;
@property (nonatomic) int voltage;

@end

// Appliance.m
@implementation Appliance

// Xcode 4.4では、@synthesizeを書かなくても、実装がない@propertyを自動生成する

@end

 上記の実装ファイルは、次に示す実装ファイルと同じものになります。

// Appliance.m
@implementation Appliance
{
    NSString *_productName;
    int _voltage;
}

- (void)setProductName:(NSString*)productName
{
    _productName = [productName copy];
}
- (NSString*)productName
{
    return _productName;
}
- (void)setVoltage:(int)voltage
{
    _voltage = voltage;
}
- (int)voltage
{
    return _voltage;
}

@end

Appleは、インスタンス変数の先頭にアンダースコア(_)を付与することを推奨しています。デフォルト@synthesizeによって自動生成されるインスタンス変数も、_productNameのように先頭にアンダースコアが付与されることに注意してください(@synthesizeを記述した場合に自動生成されるインスタンス変数は、今までどおりアンダースコアは付きません)
先頭にアンダースコアを付与するのは、インスタンス変数だけにしてください(たとえば、先頭にアンダースコアを付与したメソッドはAppleにより予約されています)。

Objective-Cリテラルの追加

NSString@"string"というリテラルがありますが、これに加えて、NSArrayNSDictionaryNSNumberに対するリテラルが追加されました。
まず、NSArrayリテラルの例です。

// NSArrayの生成(Xcode 4.3以前)
NSArray *colors = [NSArray arrayWithObjects:
                   @"Orange", @"Yellow", @"Green", nil];

// NSArrayの生成(Xcode 4.4)
NSArray *colors = @[@"Orange", @"Yellow", @"Green"]; // nilは不要!

次に、NSDictionaryリテラルの例です。

// NSDictionaryの生成(Xcode 4.3以前)
NSArray* titles = [NSArray arrayWithObjects:@"CEO", @"CTO", nil];
NSArray* persons = [NSArray arrayWithObjects:firstPerson, secondPerson, nil];
NSDictionary *executives = [NSDictionary dictionaryWithObjects:persons
                                                       forKeys:titles];
// NSDictionaryの生成(Xcode 4.4)
NSDictionary *executives = @{@"CEO" : firstPerson,
                             @"CTO" : secondPerson};

そして、NSNumberリテラルの例です。

// NSNumberの生成(Xcode 4.3以前)
NSNumber *number = [NSNumber numberWithInt:4];

// NSNumberの生成(Xcode 4.4)
NSNumber *number = @4;

式の評価結果をNSNumberリテラルとすることもできます。

// 式を使ったNSNumberの生成(Xcode 4.4)
NSNumber *number = @(1+2);

C言語文字列からNSStringに変換する式リテラルも追加されました(ただし、サポートしている文字エンコーディングはUTF-8とASCIIだけになります)。

char *greeting = "Hello!";

// C言語文字列からNSStringへの変換(Xcode 4.3以前)
NSString *x = [NSString stringWithCString:greeting
                                 encoding:NSUTF8StringEncoding];  

// C言語文字列からNSStringへの変換(Xcode 4.4)
NSString *x = @(greeting);

これらの新しいリテラルにより、第26章のStockzプログラムは次のように簡素に記述することができます。

@autoreleasepool {
    // 2つのNSDictionaryを持つNSArrayの生成(Xcode 4.4)
    NSArray *stocks = @[@{@"symbol" : @"AAPL", @"shares" : @200},
                        @{@"symbol" : @"GOOG", @"shares" : @160}];

     [stocks writeToFile:@"/tmp/stocks.plist"
              atomically:YES];
    ...
}

ここに示したリテラルは、コンパイラによってメソッド呼び出しによるコードに変換されます。そのため、これらのリテラルを静的変数やグローバル変数の初期値に使うことはできません。

Objective-Cコンテナの添字指定

NSArrayNSDictionaryといったコレクションの要素のアクセスに、C言語配列のように[]を使った添字指定が使えるようになりました(コンテナとは「入れ物」の意味です。コレクションと同じものと考えてさしつかえありません)。
まず、NSArray/NSMutableArrayの添字指定の例です。

// 0番目の要素のアクセス(Xcode 4.3以前)
NSDate *date = [dateList objectAtIndex:0];
[dateList replaceObjectAtIndex:0 withObject:now];

// 0番目の要素のアクセス(Xcode 4.4)
NSDate *date = dateList[0];
dateList[0] = now;

次に、NSDictionary/NSMutableDictionaryの添字指定の例です。

// @"symbol"キーに対応する要素のアクセス(Xcode 4.3以前)
NSString *symbol = [stocks objectForKey:@"symbol"];
[stocks setObject:@"AAPL" forKey:@"symbol"] ;

// @"symbol"キーに対応する要素のアクセス(Xcode 4.4)
NSString *symbol = stocks[@"symbol"];
stocks[@"symbol"] = @"AAPL";

■OS X 10.7とiOS 5.1に関する注意点

ここで紹介した機能は、すべてXcode 4.4に含まれるコンパイラ(LLVMコンパイラ 4.0)によって実現されています。そのため、Xcode 4.4がサポートするOS X 10.7やiOS 5.1でもこれらの機能を使うことができますが、次の制約があります。

・コンテナの添字指定は使えません。
NSNumberのブール値リテラル(@YES/@NO)は使えません。

この制約を回避するためには、次のコードをプロジェクトに含めます(プロジェクトの-Prefix.pchファイルに記述してもよいでしょう)。

// OS X 10.7/iOS 5.1の場合
#if __MAC_OS_VERSION_MAX_ALLOWRD < 1080 || \
    __IPHONE_OS_VERSION_MAX_ALLOWRD < 6000

// 添字指定を使うためには、カテゴリとしてインターフェイスを宣言するだけでよく、
// 実装は必要ない
@interface NSArray(subscripting)
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
@end

@interface NSMutableArray(subscripting)
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
@end

@interface NSDictionary(subscripting)
- (id)objectForKeyedSubscript:(id)key;
@end

@interface NSMutableDictionary(subscripting)
- (void)setObject:(id)obj forKeyedSubscript:(id )key;
@end

// @YES/@NOを使うためには、YES/NOを括弧で囲んだもので再定義する
#undef YES
#undef NO
#define YES ((BOOL)1)
#define NO  ((BOOL)0)

#endif

チャレンジ

今まで作成したFoundationプロジェクトを、Modern Objective-Cの構文に合うように書き直してください。Xcode 4.4には既存コードをある程度まで変換する機能があります。[Edit]→[Refactor]→[Convert to Modern Objective-C Syntax...]と選んでください
また、Appleの指針に合うように、
  • インスタンス変数は@implementationブロックに記述し、先頭にアンダースコアを付与すること
  • init/dealloc/カスタムアクセサの中ではインスタンス変数にアクセスし、それ以外の場所ではアクセサを使うこと
も忘れないでください。

✍ インスタンス変数の定義の先頭にアンダースコアを付与してからビルドすると、エラーと修正候補が表示されます。ここで[Editor]→[Fix All in Scope]を選ぶと、すべての修正候補が反映されます。