ARC への移行の公開ノート
自動参照カウント(ARC)は、Objective-C のオブジェクトの自動メモリ管理を提供するコンパイラの機能です。解放と保持の操作を考えることよりも、ARC は興味深いコード、オブジェクトグラフ、およびアプリケーション内のオブジェクト間の関係に集中することができます。
要約
ARC は、オブジェクトが必要な限り生きていますが、そうでない場合、保証しないため、コンパイル時にコードを追加することで機能します。概念的には、それは適切なメモリ管理を追加することで (高度なメモリ管理プログラミングガイド を参照)、手動参照カウントと同じメモリ管理規則に従います。
コンパイラが正しいコードを生成するために、ARC は、使用できるメソッドを制限し、自由通話ブリッジングを使用する方法(通話無料でブリッジされた型 を参照してください)を制限します。ARC は、またオブジェクト参照と 宣言されたプロパティ の、生涯に亘り資格を満たす物を導入します。
ARC は OS X 10.6 および v10.7(64 ビット·アプリケーション) と iOS 4 と iOS 5 で Xcode 4.2 上でサポートされています。弱い参照は、OS X 10.6 と iOS 4 ではサポートされません。
Xcode は(保持と、解放の呼び出しの削除など)の ARC 変換の機械的な部分を自動化し、( [編集]> [リファクタリング]>[Objective-C の ARC に変換]を選択します)移行ツールが自動的に処理できない問題を修正するのに役立つツールを提供しています。移行ツールは、ARC を使用するには、プロジェクト内のすべてのファイルを変換します。また、いくつかのファイルのマニュアル参照カウントを使用するのがより便利であればファイル単位で ARC を使用するように選択ができます。
以下も参照の事:
ARCの概要
保持(retain)、解除(release)、自動解放(autorelease) を使用する際に覚えておく代わりに、ARCは、オブジェクトの有効期間の要件を評価し、自動的に適切なメモリ管理を、コンパイル時に挿入します。コンパイラは、また適切な dealloc メソッドを生成します。通常、ARC だけを使用している場合は、手動の参照カウントを使用するコードと相互運用する必要がある場合にのみ一、伝統的なココアの命名規則が重要です。
Person クラスの完全かつ正確な実装は次のようになります。
@interface Person : NSObject @property NSString *firstName; @property NSString *lastName; @property NSNumber *yearOfBirth; @property Person *spouse; @end @implementation Person @end
(オブジェクトのプロパティは、デフォルトでは強い(strong)です。強い属性は、ARC は新しい、生涯に亘り資格を満たす物を導入 で説明します)
ARC を使用して、このような不自然なメソッドを実装できます。
- (void)contrived { Person *aPerson = [[Person alloc] init]; [aPerson setFirstName:@"William"]; [aPerson setLastName:@"Dudney"]; [aPerson setYearOfBirth:[[NSNumber alloc] initWithInteger:2011]]; NSLog(@"aPerson: %@", aPerson); }
Person も NSNumber オブジェクトのいずれもがリークしないように、ARC が、メモリ管理を処理します。
また、Person の takeLastNameFrom: メソッドを以下の様に安全に実装することができます。
- (void)takeLastNameFrom:(Person *)person { NSString *oldLastname = [self lastName]; [self setLastName:[person lastName]]; NSLog(@"Lastname changed from %@ to %@", oldLastname, [self lastName]); }
ARC は oldLastName がの NSLog 文の前に解放されないことを保証します。
ARC は新ルールを強要
動く為に、ARC は、他のコンパイラモードを使用するときには存在しないいくつかの新しいルールを課している。ルールは、完全に信頼性のあるメモリ管理モデルを提供することを意図している。いくつかの場合には、それらは単に、最良の実行を課する他に、それらはコードを簡略化したり、メモリ管理に対処する必要がないのは明らかな結論です。これらのルールに違反した場合は、実行時に明らかになることがある微妙なバグではなく、すぐにコンパイル時エラーになります。
禁止は、@selector(retain)、@selector(release) の使用などに拡張します。
インスタンス変数を解放する以外にリソースを管理するための必要がある場合は、dealloc メソッドを実装することができる。インスタンス変数を解放する必要はありませんが、(確かにすることはできません)システムクラスと ARC を使用してコンパイルされていない他のコードでは、[systemClassInstance setDelegate:nil] を起動する必要があります。
ARC のカスタムの dealloc メソッドの呼び出しは、[supert dealloc](それは実際にはコンパイルエラーとなる)を必要としません。super への連鎖は、コンパイラによって自動化され、実施されます。
まだ(通信自由ブリッジの管理を参照)CFRetain、CFRelease、およびコア・ファンデーション・スタイル・オブジェクトと関連した他の機能を使用することができます。
alloc を使用してオブジェクトを作成します。ランタイムは、オブジェクトの割り当てを解除してくれます。
struct を使用するのではなく、その代わりに、データを管理するために、Objective-C のクラスを作成することができます。
オブジェクトの有効期間についてコンパイラに伝える特別なキャストを使用しなければなりません。Objective-C のオブジェクトと、関数の引数として渡す Core Foundation の型の間でキャストするためにこれを行う必要があります。詳細については、通信自由ブリッジの管理を参照してください。
ARC は、代わりに @autoreleasepool ブロックを提供します。これらは、NSAutoreleasePool よりも効率的であるという利点があります。
これ以上 NSZone を使用する必要はありません-それらは現代の Objective-C ランタイムによってとにかく無視されます。
手動の保持・解除コードとの相互運用を可能にするために、ARC はメソッドの名前付けに制約を課しています:
// Won't work: @property NSString *newTitle; // Works: @property (getter=theNewTitle) NSString *newTitle;
ARC は新しい、生涯に亘り資格を満たす物を導入
ARC は、オブジェクトのいくつかの新しい生涯に亘り資格を満たす物を導入、弱参照を導入しています。弱い参照は、それが指すオブジェクトの有効期間を延長せず、オブジェクトへの強い参照がない場合に自動的に nil にはなりません。
プログラムでオブジェクトグラフを管理するために、これらの資格を満たすものを利用して下さい。具体的には、ARC は(循環保持として以前知られていた- 実践メモリ管理 を参照) 強い循環参照 を防げません。弱い関係を適切に使用すれば、循環参照を作成しないのに役立ちます。
プロパティの属性
以下の例に示すように weak と strong のキーワードは、宣言された新しいプロパティ属性として導入されます。
// The following declaration is a synonym for: @property(retain) MyClass *myObject; @property(strong) MyClass *myObject; // The following declaration is similar to "@property(assign) MyClass *myObject;" // except that if the MyClass instance is deallocated, // the property value is set to nil instead of remaining as a dangling pointer. @property(weak) MyClass *myObject;
ARC の下で、strong がオブジェクト型のデフォルトです。
変数の資格を満たすもの
const に代わり、変数に対する、次の生涯に亘り資格を満たすものを使用して下さい。
__strong __weak __unsafe_unretained __autoreleasing
正しく変数を飾る必要があります。オブジェクト変数の宣言に修飾子を使用する場合は、正しい形式は次のとおりです:
ClassName * qualifier variableName;
例えば:
MyClass * __weak myWeakReference; MyClass * __unsafe_unretained myUnsafeReference;
他の変異体は、技術的には間違っていますが、コンパイラに「許され」ます。問題を理解するには、http://cdecl.org/ を参照してください。
スタック上で __weak 変数を使用する際は注意してください。次の例は動きます:
NSError *error; BOOL OK = [myObject performOperationWithError:&error]; if (!OK) { // Report the error. // ...
ただし、エラー宣言は暗黙的です。
NSError * __strong e;
そして、メソッドの宣言は、一般的に次のようになります:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
コンパイラは、そのためコードをこのように書き換えます:
NSError * __strong error; NSError * __autoreleasing tmp = error; BOOL OK = [myObject performOperationWithError:&tmp]; error = tmp; if (!OK) { // Report the error. // ...
ローカル変数宣言(__strong) とパラメータ(__autoreleasing) の間のミスマッチで、一時的な変数を作成するようにコンパイラーにさせます。パラメータ id__strong * を宣言することで__strong 変数のアドレスを取るとき、元のポインタを得られます。別の方法としては、__autoreleasing として変数を宣言することができます。
強い循環参照を回避するために生涯に亘り資格を満たすものを使用
強力な循環参照を避けるために、生涯に亘り資格を満たすものを使用することができます。例えば、親子階層と親がその子どもへの参照が必要な時とその逆が配置されたオブジェクトのグラフがある場合は、親から子への関係を強く、また子から親への関係を弱く作って下さい。他の状況では、それらは ブロックオブジェクト を伴う場合は特に、より微妙な場合があります。
マニュアル参照カウントモードでは、__block id x; は x を保持する効果はありません。ARC モードでは、__block id x; は(ちょうど他のすべての値のように)x を保持するのがデフォルトです。 ARC の下にマニュアル参照カウントモードの動作を得るには、__unsafe_unretained __block id x; を使用することができます。__unsafe_unretained は、名前が示すように(それがぶら下がるる可能性があるため)、非保持変数を持つことは危険ですので、お勧めしません。二つの、より良いオプションは、保持悪循環を断ち切るために(iOS 4 または OS X10.6 をサポートする必要がない場合)__weak を使用するか、nil を__block 値に設定するかです。
次のコード断片は、場合によっては、手動参照カウントで使用されるパターンを使用して、この問題を示しています。
MyViewController *myController = [[MyViewController alloc] init…]; // ... myController.completionHandler = ^(NSInteger result) { [myController dismissViewControllerAnimated:YES completion:nil]; }; [self presentViewController:myController animated:YES completion:^{ [myController release]; }];
上述したように、代わりに、__block 修飾子を使用し、nil を完了ハンドラの myController 変数に設定します。
MyViewController * __block myController = [[MyViewController alloc] init…]; // ... myController.completionHandler = ^(NSInteger result) { [myController dismissViewControllerAnimated:YES completion:nil]; myController = nil; };
別の方法として、一時的に、__weak 変数を使用することができます。次の例は、簡単な実装を示しています。
MyViewController *myController = [[MyViewController alloc] init…]; // ... MyViewController * __weak weakMyViewController = myController; myController.completionHandler = ^(NSInteger result) { [weakMyViewController dismissViewControllerAnimated:YES completion:nil]; };
しかしながら、平凡でないサイクルでは、以下のように:
MyViewController *myController = [[MyViewController alloc] init…]; // ... MyViewController * __weak weakMyController = myController; myController.completionHandler = ^(NSInteger result) { MyViewController *strongMyController = weakMyController; if (strongMyController) { // ... [strongMyController dismissViewControllerAnimated:YES completion:nil]; // ... } else { // Probably nothing... } };
クラスが __weak と互換性がない場合、いくつかのケースでは、__ unsafe_unretained を使用することができます。それは、__ unsafe_unretained ポインタはまだ有効で、まだ問題になっている同じオブジェクトを指していることを検証するのは難しい、あるいは不可能であることがありうるので、これは、重要なサイクルのための非現実的になることがあります。
ARC は、自動解放プールを管理するための新しい宣言を使用
ARC を使用すると、直接 NSAutoreleasePool クラスを使用して自動解放プールを管理することはできません。代わりに、@autoreleasepool ブロックを使用します。
@autoreleasepool { // Code, such as a loop that creates a large number of temporary objects. }
この単純な構造で、コンパイラが参照カウントの状態について推論することができます。エントリーでは、自動解放プールがプッシュされます。正常終了時(ブレーク、リターン、goto、fall-through など)、自動解放プールはポップされます。出口は例外が原因であれば、既存のコードとの互換性を確保するため、自動解放プールはポップされません。
この構文は、すべての Objective-C モードで使用可能です。これは、NSAutoreleasePool クラスを使用するよりも効率的です。したがって、NSAutoreleasePool を使用する代わりにそれを採用することをお勧めします。
アウトレットを管理するパターンはプラットフォーム間で一貫する
iOS と OS X で アウトレット を宣言するパターンは、ARC で変化し、両方のプラットフォームで一貫したものとなりました。一般的に 採用すべきパターンは、次のとおりです:アウトレットは weak であるべきで、nib ファイル内のトップレベルのオブジェクト(またはストーリーボードシーン) へのファイルの所有者からのものは strong であるべきだが、それを除けば。
完全な詳細は、リソース·プログラミング·ガイド の nib ファイル に記載されています。
スタック変数は nil で初期化されます
ARC を使用すると、strong、weak、および autoreleasing スタック変数は暗黙的に nil で初期化されます。たとえば、次のように:
- (void)myMethod { NSString *name; NSLog(@"name: %@", name); }
むしろ、おそらくクラッシュより name の値に null を入れ、ログに記録します。
ARC を有効/無効にするコンパイラフラグを使用
新しい -fobjc-arc コンパイラフラグを使用して、 ARC を有効にしてください。また、いくつかのファイルのマニュアル参照カウントの使用がより便利であればファイル単位で ARC を使用するように選択することができます。デフォルトのアプローチとして ARC を採用するプロジェクトでは、そのファイルの新しい -fno-objc-arc のコンパイラフラグを使用して特定のファイルで ARC を無効にすることができます。
ARC は、Xcode 4.2 以降でサポートされ、OS X v10.6以降(64ビット·アプリケーション)と iOS 4 以降用とされています。弱い参照は、OS X v10.6 と iOS 4 ではサポートされていません。Xcode 4.1 以前のバージョンには ARC のサポートはありません。
通信自由ブリッジの管理
多くの Cocoa アプリケーションでは、コアグラフィックス(CGColorSpaceRef と CGGradientRef のようなタイプを使えます)のようなコア・ファウンデーション代表を採用した(例えば CFArrayRef や CFMutableDictionaryRef など)フレームワークから、あるいはコア・ファウンデーション・フレームワーク自体から、コア・ファウンデーションのスタイルのオブジェクトを使用する必要があります。
コンパイラは自動的にはコア・ファウンデーションのオブジェクトの寿命を管理しません。コア・ファウンデーションのメモリ管理規則によって指示されるように(Core Foundation のためのメモリ管理プログラミングガイド を参照)CFRetain と CFRelease(または対応するタイプ固有亜種)を呼び出す必要があります。
Objective-C とコア・ファウンデーションのスタイルのオブジェクト間でキャストする場合は、(ObjC/runtime.h で定義されている)キャストや、コア・ファウンデーションのスタイルのマクロ(NSObject.h で定義されている)いずれかを使用してオブジェクトの所有権の意味について、コンパイラに指示する必要があります。
あなたは、オブジェクトの所有権を放棄する CFRelease または関連した関数を呼出す責任があります。
ARC は、オブジェクトの所有権を放棄する責任があります。
たとえば、次のようなコードがあった場合:
- (void)logFirstNameOfPerson:(ABRecordRef)person { NSString *name = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty); NSLog(@"Person's first name: %@", name); [name release]; }
これを以下のように置き換えます:
- (void)logFirstNameOfPerson:(ABRecordRef)person { NSString *name = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); NSLog(@"Person's first name: %@", name); }
コンパイラは、ココアメソッドから返される CF オブジェクトを扱う
コンパイラは、コア・ファウンデーションの型は、歴史的な Cocoa の命名規則(高度なメモリ管理プログラミングガイド を参照してください)に従う Objective-C のメソッドを理解します。例えば、コンパイラは、iOS では、UIColor のメソッド CGColor で返される CGColor は、所有されていません。まだ、以下の例で示すように、適切なタイプキャストを使用しなければなりません。
NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]]; [colors addObject:(id)[[UIColor lightGrayColor] CGColor]];
所有権のキーワードを用いてキャストファンクションのパラメータ
関数呼び出しで Objective-C とコア・ファウンデーションのオブジェクト間のキャストするときには、渡されたオブジェクトの所有権の意味についてコンパイラに指示する必要があります。コア・ファウンデーションのオブジェクトの所有権の規則は(Core Foundation のためのメモリ管理プログラミングガイド を参照)コア・ファウンデーションのメモリ管理規則で指定されたものです。 Objective-C のオブジェクトのための規則は、高度なメモリ管理プログラミングガイド で指定されています。
以下のコードの断片では、配列は CGGradientCreateWithColors 関数に渡され、適切なキャストが必要です。arrayWithObjects: によって返されるオブジェクトの所有権は、関数に渡されておらず、以下のようにキャストは __bridge です。
NSArray *colors = <#An array of colors#> CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
コードの断片は、次のメソッド実装文脈で示されている。コア・ファウンデーションのメモリ管理規則によって決定される、コア・ファウンデーションのメモリー管理関数を使用する事を注意されたい。
- (void)drawRect:(CGRect)rect { CGContextRef ctx = UIGraphicsGetCurrentContext(); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); CGFloat locations[2] = {0.0, 1.0}; NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]]; [colors addObject:(id)[[UIColor lightGrayColor] CGColor]]; CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations); CGColorSpaceRelease(colorSpace); // Release owned Core Foundation object. CGPoint startPoint = CGPointMake(0.0, 0.0); CGPoint endPoint = CGPointMake(CGRectGetMaxX(self.bounds), CGRectGetMaxY(self.bounds)); CGContextDrawLinearGradient(ctx, gradient, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation); CGGradientRelease(gradient); // Release owned Core Foundation object. }
プロジェクトの変換での一般的な問題
既存のプロジェクトを移行するときには、様々な問題に遭遇する可能性があります。ここで一緒に、いくつかの一般的な問題と、解決策を示します。
- retain,release, または autorelease を呼び出す事はできません。
- dealloc を呼び出すことはできません。
- NSAutoreleasePool オブジェクトを使用することはできません。
- ARC は、init メソッド内の self に [super init] の結果を割り当てる必要があります。
- カスタムの retain や release メソッドの実装はできません。
- パフォーマンス。
- カスタムの弱いポインタシステムを実装する。
- シングルトンクラスを実装する。
- 「割り当てられた」インスタンス変数は strong になる。
- C の構造体に強い id を使用することはできません。
- 構造体の代わりに、Objective-C のオブジェクトを使用します。
これは、とにかく最良の実践であると考えられます。
- Objective-C のオブジェクトを使用するのが、次善であれば(多分これらの構造体の濃い配列が欲しいのでしょう)、代わりに void * の使用を検討してください。
これは、後述する明示的なキャストを、使用する必要があります。
- _ unsafe_unretained としてオブジェクト参照をマークします。
このアプローチは、以下のような半分一般的なパターンで役に立つことがあります。
struct x { NSString *S; int X; } StaticArray[] = { @"foo", 42, @"bar, 97, ... };
以下のように構造体を宣言します:
struct x { NSString * __unsafe_unretained S; int X; }
オブジェクトがポインタの下から解放されれば、これが問題・危険となるが、文字列リテラル定数のように永遠に近くなることが知られているものでは非常に有用です。
- 直接 id と void * の間でキャストすることはできません(コア・ファウンデーションの型を含む)。
これは仕様です。以下のように書くこともできません。
while ([x retainCount]) { [x release]; }
シングルトンを実装するか、init メソッドでオブジェクトを置き換える場合には、通常の dealloc を呼び出します。シングルトンの場合は、共有インスタンス·パターンを使用します。init のメソッドでは、self を上書きしたときにオブジェクトが解放されますので、もう dealloc を呼び出す必要はありません。
新しい @autoreleasepool{} 構造を代わりに使って下さい。これは、自動解放プールにブロック構造を強制し、NSAutoreleasePool の約6倍の速さです。@autoreleasepool は ARC コードでなくても動作します。@autoreleasepool は NSAutoreleasePool よりもとても速いので、多くの古い「パフォーマンスハック」は単に無条件の @autoreleasepool に置き換えられます。
移行者は NSAutoreleasePool を簡単に使いますが、それは複雑な条件の場合や、変数が新しい @autoreleasepool の本体内部で定義され、その後に使用されているケースを処理することはできません。
以下は、ARC の init メソッドでは無効です。
[super init];
簡単に直すと以下のようになります
self = [super init];
適切な修正はそれを行い、そして 続行する前に nil かどうか、結果をチェックして下さい。
self = [super init]; if (self) { ...
カスタムの retain や release メソッドを実装すると、弱いポインタを壊します。カスタム実装を提供したい、いくつかの一般的な理由があります。
これを実行しないでください。NSObject の retain や release の実装は、今ははるかに高速になりました。それでも問題が見つかった場合は、バグを提出してください。
代わりに、__weak を使用してください
代わりに、共有インスタンス·パターンを使用してください。代替的に、オブジェクトを全く割り当てる邪魔をする、インスタンスメソッドの代わりに、クラスを使用します。
ARC より前は、インスタンス変数は、オブジェクトの寿命を延長しなかったインスタンス変数にオブジェクトを割り当て参照-直接所有しませんでした。プロパティを強くするには、通常、実装するか、適切なメモリー管理方法を起動したアクセサメソッドを合成しました。対照的に、弱いプロパティを維持するために、次の例に示すようなアクセサメソッドを実装する場合があります。
@interface MyClass : Superclass { id thing; // Weak reference. } // ... @end @implementation MyClass - (id)thing { return thing; } - (void)setThing:(id)newThing { thing = newThing; } // ... @end
ARC では、インスタンス変数はデフォルトで強い参照をし、オブジェクトから直接インスタンス変数に割り当てするのは、オブジェクトの寿命を延長します。移行ツールは、インスタンス変数が弱い傾向にある時を決定することはできません。以前と同じ動作を維持するには、インスタンス変数を弱いものとしてマークし、または宣言されたプロパティを使用しなければなりません。
@interface MyClass : Superclass { id __weak thing; } // ... @end @implementation MyClass - (id)thing { return thing; } - (void)setThing:(id)newThing { thing = newThing; } // ... @end
または:
@interface MyClass : Superclass @property (weak) id thing; // ... @end @implementation MyClass @synthesize thing; // ... @end
たとえば、次のコードはコンパイルされません。
struct X { id x; float y; };
これは、X がデフォルトで強く保持するために、コンパイラが安全に、正しく動作させるために必要なすべてのコードを合成することができないためです。例えば、free になるいくつかのコードを、これらの構造の一つへのポインタを渡す場合、各 id は、struct が解放される前に解放されなければならない。コンパイラは、確実にこれを行うことはできないし、構造体内では強力な id は ARC モードで完全に禁止されています。いくつかの可能な解決策があります。
この事は「通信自由ブリッジの管理」で詳しく説明されています。
よくある質問
どのよう ARC を考えたらいいですか?どこに retain/release を置くのですか?
retain/release 呼び出しをどこに置いたらいいか考えるのはよして、代わりに、アプリケーションのアルゴリズムを考えて下さい。オブジェクトの「強弱」ポインタについて、オブジェクトの所有権、および可能な保持のサイクルについて考えて下さい。
まだオブジェクトのための dealloc メソッドを記述する必要がありますか?
多分
コア・ファウンデーションのオブジェクト、ファイル記述子など、それらのリソースを ARC は dealloc メソッドを記述することによって寿命の管理や malloc/free、の自動化していないためです。
(実際にはできない)インスタンス変数を解放する必要はありませんが、システム·クラスと ARC を使用してコンパイルされていない他のコードでは[self setDelegate:nil] を起動する必要があります。
ARC では dealloc メソッドは[super dealloc] を呼出す必要もなく、許されてもいません。super への連鎖は、実行時に処理され、実施されている。
ARC では、rtain のサイクルはまだ可能ですか?
はい。
ARC は retain/release を自動化し、retain サイクルの問題を継承します。幸いなことに、プロパティが retain しているかどうかをすでに宣言しているため、ARC に移行したコードはまれにしかメモリーリークしません。
ARC ではブロックはどのように働きますか?
リターンの時のように ARC モードのスタックを、ブロックを渡すときのようにブロックは"仕事をよくこなす"。これ以上ブロックコピーを呼び出す必要はありません。まだ arrayWithObjects: にスタックを「ダウン」するときに、[^{} copy] を使用する必要がありますし、他のメソッドが retain します。
注意すべきことの一つは、NSString * __block myString は、ARC モードでは retain され、ぶら下がりポインタではないことです。以前の動作を取得するには、__block NSString * __unsafe_unretained myString か(もっとよくは)__block NSString * __weak myString
を使用します。スノーレパードを使用して ARC と OS X 用のアプリケーションを開発できますか?
いいえ。それは 10.7 の SDK が含まれていないので、Xcode 4.2 のスノーレパードのバージョンは、まったく OS X 上で ARC をサポートしていません。スノーレパードのための Xcode 4.2 は、しかし iOS 用の ARC をサポートして、ライオンのための Xcode 4.2 は、OS X と iOS の両方をサポートしています。これは、スノーレパードの上で動作する ARC アプリケーションをビルドするためにライオンのシステムが必要な事を意味します。
ARC の下で retain されたポインタの C 配列を作れますか?
はい、以下の例で示すように、できます:
// Note calloc() to get zero-filled memory. __strong SomeClass **dynamicArray = (__strong SomeClass **)calloc(entries, sizeof(SomeClass *)); for (int i = 0; i < entries; i++) { dynamicArray[i] = [[SomeClass alloc] init]; } // When you're done, set each entry to nil to tell ARC to release the object. for (int i = 0; i < entries; i++) { dynamicArray[i] = nil; } free(dynamicArray);
注意すべき点がいくつかあります。
ARC は遅いですか?
それはあなたが何を測定しているかに依存しますが、一般的に「いいえ」です。コンパイラが効率的に多くの余分な retain/release コールを取り除き、一般的に Objective-C 実行時の速度向上に多くの努力がつぎ込まれて来ました。具体的には、一般的な「retain/autorelease オブジェクトを返す」パターンもはるかに高速で、メソッドの呼び出し元が ARC コードの場合に、実際に自動解放プールの中にオブジェクトを置きません。
注意すべき一つの問題は、最適化が、共通のデバッグ構成で実行されず、その多くは、-Os より -O0 で、retain/release のトラフィックを見ることでしょう。
ARC は ObjC++ モードで動作しますか?
はい。クラスやコンテナに strong/weak の id を入れることができます。ARC コンパイラは、この作業を完成させるためにコンストラクタやデストラクタをコピーし、retain/release ロジックを合成する。
どのクラスが弱い参照をサポートしていないですか?
現在、以下のクラスのインスタンスへの弱い参照を作成することはできません。
NSATSTypesetter、NSColorSpace、NSFont、NSMenuView、NSParagraphStyle、NSSimpleHorizontalTypesetter, そしてNTTextViewer.
注意:また、OS X v10.7 では、NSFontManager、NSFontPanel、NSImage、NSTableCellView、NSViewController、NSWindow、 そして NSWindowController のインスタンスへ弱い参照を作成はできません。また、OS X v10.7 内では AV Foundation のフレームワークは全てのクラスは弱い参照をサポートしません。
宣言されたプロパティの場合は、weak の代わりに assign を使用する必要があります。変数に対しては、__weak の代わりに__unsafe_unretained を使用する必要があります。
さらに、ARC の下 NSHashTable、NSMapTable、 または NSPointerArray のインスタンスから弱い参照を作成することはできません。
NSCell や NSCopyObject を使用する別のクラスをサブクラス化する際に何をしなければならないのですか?
特別な事は何もない。ARC は、以前に明示的に保持を追加する必要があった例の面倒を見ます。ARC では、すべてのコピーメソッドは、単にインスタンス変数をコピーします。
特定のファイルでは ARC から手を引くことはできますか?
はい。
ARC を使用するようにプロジェクトを移行する場合、-fobjc-arc のコンパイラフラグは、Objective-C のソースファイルに全てデフォルトとして設定されています。そのクラスに -fno-objc-arc のコンパイラフラグを使用して、特定のクラスで ARC を無効にすることができます。Xcode で、[ターゲットビルドフェーズ]タブで、ソースファイルのリストを表示するために[ソースグループをコンパイル]を開きます。フラグを設定したいファイルをダブルクリックし、ポップアップ·パネルで -fno-objc-arc を入力し、[完了]をクリックします。
GC(ガベージコレクション)は、Mac 上では旧式となったのですか?
ガベージコレクションは、OS X マウンテンライオンの v10.8 で廃止され、かつ OS Xの将来のバージョンでは削除される予定です。自動参照カウントは、推奨される代替技術です。既存のアプリケーションの移行を支援するために、Xcode 4.3 以降の ARC 移行ツールは、ガベージコレクションを使った OS X アプリケーションを ARC に移行するのをサポートします。
注意:Mac App Store を対象としたアプリのために、Apple は Mac App Store のガイドラインは旧式の技術の使用を禁止する(Mac アプリ用の App Store レビューガイドラインを参照) ので、できるだけ実現可能な限り早く、ARC でガベージコレクションを置き換えることを強くお勧めします。