ARCへの移行のリリースノート

2013. 05. 03
自動参照カウント(ARC:Automatic Reference Counting)は、Objective-Cオブジェクトの自動メモリ管理を提供するコンパイラの機能です。
ARCによって保持や解放の操作について考えることなく、アプリケーション内のオブジェクト間の関係やオブジェクトグラフ、面白いコードに集中することができます。

ARC_design_final.gif



●要約

ARCはコンパイル時にコードを追加することによって作用し、オブジェクトが必要である限り存続し、そうでない時は破棄することを保証します。
概念としては、手動参照カウント(『高度なメモリ管理プログラミングガイド』参照)と同じメモリ管理規則に従い、適切なメモリ管理の呼び出しを追加します。

コンパイラが適切な正しいコードを生成できるように、ARCでは使用することができるメソッドと、Toll-Free Bridging(『Toll-Free Bridged Types』参照)の使用方法を制限しています。

ARCは(64bitアプリケーションの)OS X v10.6とv10.7用のXcode 4.2、およびiOS 4とiOS 5でサポートされています。
ただし弱い参照はOS X v10.6とiOS 4ではサポートされていません。

Xcodeは(retainやreleaseの呼び出しを削除するなど)機械的な部品を自動でARCへ変換したり、自動処理で移行できない問題を修正するために役立つツール(Edit > Refactor > Convert to Objective-C ARC)を提供しています。
移行ツールはARCを使用するようにプロジェクト内の全てのファイルを変換します。
手動参照カウントを使用する方が便利なファイルがいくつかある場合、ファイル単位でARCを使用するかを選択することもできます。

参照
高度なメモリ管理プログラミングガイド
Memory Management Programming Guide for Core Foundation



●ARCの概要

retainrelease、そしてautoreleaseを何時使用しているかを覚えておく代わりに、ARCがオブジェクトの寿命の要件を評価し、コンパイル時に適切なメモリ管理の呼び出しを自動的に挿入します。
またコンパイラは適切なdeallocメソッドも生成します。
一般的にARCのみを使用する場合、従来のCocoa命名規則は手動参照カウントを使用するコードとの相互処理する必要がある場合のみ重要です。

Personクラスの完全かつ正確な実装は以下のようになります。

@interface Person : NSObject
@property NSString *firstName;
@property NSString *lastName;
@property NSNumber *yearOfBirth;
@property Person *spouse;
@end

@implementation Person
@end

(オブジェクトプロパティはデフォルトでstrongです。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);
}

ARCはPersonもNSNumberオブジェクトリークしないように、メモリ管理の面倒をみます。

また次のように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を使用するにあたり、他のコンパイラモードを使用する時には存在しない、いくつかの新規則が課せられています。
規則は完全に信頼できるメモリ管理モデルを提供することを意図しており、いくつかの場合は単に最善慣行を適用し、他のいくつかの場合はコードの簡素化や貴方が処理しないメモリ管理の明白な必然の結果です。
これらの規則を破った場合、実行時に露見する潜在的なバグではなく、コンパイル時にただちにエラーとなります。
  • 明示的にdeallocの呼び出しや実装、またはretain、release、retainCount、autoreleaseの呼び出しはできません。
    この禁止は@selector(retain)、@selector(release)などの使用にまで及びます。

    インスタンス変数を解放する以外にリソースを管理する必要がある場合は、deallocメソッドを実装してください。
    貴方がインスタンス変数を解放することはありません(実際には解放することができません)が、ARCを使用してコンパイルしていない他のコードではシステムクラス上で[systemClassInstance setDelegate:nil]を呼び出す必要があるかもしれません。

    ARC内のカスタムのdeallocメソッドで[super dealloc]を呼び出す必要はありません(実際にはコンパイルエラーとなります)。
    superの一連の処理はコンパイラによって自動的に実行されます。

    CFRetainやCFRelease、その他Core Foundationスタイルオブジェクトに関連する関数は、まだ使用することができます(『Toll-Free Bridgingの管理』参照)。

  • NSAllocateObjectやNSDeallocateObjectを使用することはできません。
    オブジェクトの生成にはallocを使用し、オブジェクトの解放はランタイムが処理します。

  • Cの構造体内にオブジェクトのポインタを使用することはできません。
    structを使用する代わりに、データを管理するObjective-Cクラスを生成することができます。

  • idとvoid *間で気軽にキャストできません。
    オブジェクトの寿命についてコンパイラに伝える特別なキャストを使用する必要があります。
    Objective-CオブジェクトCore Foundation型との間のキャストをするために、関数の引数として渡す必要があります。
    詳細は『Toll-Free Bridgingの管理』を参照してください。

  • NSAutoreleasePoolオブジェクトを使用することはできません。
    代わりにARCは@autoreleasepoolブロックを提供しています。
    これらはNSAutoreleasePoolより効率的な利点を有しています。

  • メモリゾーンを使用することはできません。
    もうNSZoneを使用する必要は無く、いずれにしてもModern Objective-Cのランタイムでは無視されます。
手動参照カウントのコードとの相互処理を可能にするため、ARCはメソッドの命名に制約を課しています。
  • アクセサにnewで始まる名前を指定することはできません。
    逆言えば、例えばゲッターを別途指定しない限りnewで始まる名前のプロパティを宣言できないことを意味します。

    // Won't work:
    @property NSString *newTitle;

    // Works:
    @property (getter=theNewTitle) NSString *newTitle;

ARCで導入された新しい寿命修飾子

ARCではオブジェクトのためにいくつかの新しい寿命修飾子と弱い参照が導入されています。
弱い参照はそれが示すオブジェクトの寿命を延ばさず、オブジェクトの強い参照が無くなると自動的にnilになります。

プログラム内のオブジェクトグラフを管理するために、この修飾子を利用するべきです。
特にARCは強い参照の循環を防ぐことができません(以前から知られている保持の循環については『Practical Memory Management』参照)。
弱い関係の賢明な使用は、確実に循環参照を生成しないようにするのに役立ちます。

プロパティの属性

キーワードweakとstrongは以下の例に示すように、宣言済みプロパティの新たな属性として導入されています。

// 以下の宣言は『@property(retain) MyClass *myObject;』と同義です。
@property(strong) MyClass *myObject;

// 以下の宣言はMyClassのインスタンスが破棄された場合を除いて
// 『@property(assign) MyClass *myObject;』に相当しますが、
// プロパティ値はダングリングポインタとして残る代わりにnilに設定されます。

@property(weak) MyClass *myObject;

ARC下では、strongがオブジェクトの型のデフォルトです。

変数の修飾子

変数にはconstのように以下の寿命修飾子を使用することができます。

__strong
__weak
__unsafe_unretained
__autoreleasing

  • __strongはデフォルトです。
    オブジェクトは強いポインタが存在する限り『存続』し続けます。

  • __weakは参照しているオブジェクトが存続し続けない参照に指定します。
    弱い参照はオブジェクトへの強い参照が無くなった場合にnilに設定されます。

  • __unsafe_unretainedは参照しているオブジェクトが存続し続けない参照に指定しますが、オブジェクトへの強い参照が無くなった場合にnilに設定はしません。
    参照しているオブジェクトが解放された場合、ポインタはダングリングとして残ります。

  • __autoreleasingは引数として(id *)への参照を渡したり、戻り時に自動解放することを示す場合に使用します。

変数は正確に修飾する必要があります。
オブジェクト変数の宣言で修飾子を使用する場合の形式は次の通りです。

ClassName * qualifier variableName;

例えば

MyClass * __weak myWeakReference;
MyClass * __unsafe_unretained myUnsafeReference;

他の異種は技術的に間違っていますがコンパイラによって『許可』されています。
この問題を理解するにはhttp://cdecl.org/を参照してください。

スタック上で__weak変数を使用する場合は注意してください。
以下の例を考えてみます。

NSString * __weak string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
NSLog(@"string: %@", string);

stringは最初の代入の後で使用されていますが、代入時にstringオブジェクトへの強い参照が他に存在しないので、すぐに解放されます。
ログ文はstringがnull値を持つことを示します。
(この状況の場合、コンパイラは警告を示します。)

また参照で渡すオブジェクトにも注意する必要があります。
次のコードは動作します。

NSError *error;
BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {
    // Report the error.
    // ...

しかし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)間の不一致が、コンパイラが一時変数を生成する原因となっています。
__strong変数のアドレスを取得する時に、パラメータid __strong *を宣言することによって元のポインタを取得することができます。
あるいは__autoreleasingとして変数を宣言することもできます。

強い参照の循環を回避する寿命修飾子の使用

強い参照の循環を回避するために寿命修飾子を使用することができます。
例えば一般的に親子階層に配置されたオブジェクトのグラフを持っていて、親から子またはその逆の参照をする必要がある場合、親から子への関係は強く子から親への関係は弱くします。
その他の状況、特にブロックオブジェクトを伴う場合はより繊細です。

手動参照カウントモードでは、__block id x;はxを保持しないことになります。
ARCモードでは、__block id x;はデフォルトで(他の全ての値と同様に)xを保持します。
ARC下で手動参照カウントモードの動作を得るには、__unsafe_unretained __block id x;を使用することができます。
__unsafe_unretainedという名前が意味するように、非保持変数を持つことは(ダングリングになる可能性があり)危険なので推奨しません。
この場合(iOS 4またはOS X v10.6をサポートする必要が無い場合は)__weakを使用する方法と、保持循環を壊すために__block値をnilに設定するという、2つの良い選択肢があります。

手動参照カウントで時々使用されているパターンを用いて、この問題を以下の部分的なコードで示します。

MyViewController *myController = [[MyViewController alloc] init…];
// ...
myController.completionHandler = ^(NSInteger result) {
    [myController dismissViewControllerAnimated:YES completion:nil];
};
[self presentViewController:myController animated:YES completion:^{
    [myController release];
}];

説明の通り、代わりに__block修飾子を使用して、完了ハンドラでmyContoller変数をnilに設定することができます。

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 {
    // 多数の一時オブジェクトを生成するループなどのコード
}

この単純な構造で、コンパイラは参照カウントの状態について判断することができます。
登録すると自動解放プールはプッシュします。
正常終了(break、return、goto、fall-throughなど)すると自動解放プールはポップします。
既存のコードと互換性を保つため、exitが例外に因る場合、自動解放プールはポップしません。

この構文は全てのObjective-Cのモードで使用できます。
NSAutoreleasePoolクラスを使用するより効率的であり、NSAutoreleasePoolを使用する代わりに採用することを推奨します。


・プラットフォーム間で一貫したアウトレットの管理方式

ARCでは、iOSとOS Xにおけるアウトレットを宣言する方式が、双方のプラットフォーム間で一貫するように変更されています。
この方式では通常、nibファイル(またはストーリーボードのシーン)内のFile's Ownerからトップレベルのオブジェクトでstrongにする必要があるものを除いて、アウトレットはweakにする必要があります。

完全な詳細は『Resource Programming Guide』の『Nib Files』に記載されています。


・スタック変数はnilで初期化される

ARCを使用すると、strongとweak、そしてautoreleasingのスタック変数は、現在暗黙的にnilで初期化されます。
例えば、次の場合は

- (void)myMethod {
    NSString *name;
    NSLog(@"name: %@", name);
}

おそらくクラッシュするのではなく、nameの値としてnullがログに出力されます。


・コンパイラフラグを使用したARCの有効/無効

ARCを有効にするには、新しい-fobjc-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をサポートしません。



Toll-Free Bridgingの管理

多くのCocoaアプリケーションでは、(CFArrayRefまたはCFMutableDictionaryRefなどの)Core Foundationフレームワーク自体から、または(CGColorSpaceRefCGGradientRefのような型を使用する場合は)Core GraphicsなどのCore Foundation規則を採用するフレームワークから、Core Foundation型オブジェクトを使用する必要があります。

コンパイラはCore Foundationオブジェクトの寿命を自動的に管理しないので、Core Foundationのメモリ管理規則(『Memory Management Programming Guide for Core Foundation』参照)によって指示するCFRetainCFRelease(または対応する型固有の変種)を呼び出す必要があります。

Objective-CとCore Foundation型オブジェクト間でキャストする場合、(obj/runtime.hで定義されている)キャストまたは(NSObject.hで定義されている)Core Foundationの型マクロのどちらかを使用して、オブジェクトの所有権のセマンティクスについてコンパイラに指示する必要があります。
  • __bridgeは所有権の移行の無い、Objective-CとCore Foundation間でのポインタの転移です。

  • __bridge_retainedまたはCFBridgingRetainはObjective-CポインタをCore Foundationポインタにキャストし、所有権も貴方に移行されます。
    貴方はオブジェクトの所有権を放棄するために、CFReleaseまたは関連する関数を呼び出す責任があります。

  • __bridge_transferまたはCFBridgingReleaseは非Objective-CポインタをObjective-Cに移動し、ARCに所有権を移行します。
    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);
}


・Cocoaメソッドから返されたCFオブジェクトのコンパイラの処理

コンパイラは歴史的なCocoaの命名規則(『高度なメモリ管理プログラミングガイド』参照)に従って、Core Foundation型を返すObjective-Cメソッドを理解します。
例えばコンパイラは、iOSのUIColorCGColorメソッドによって返されるCGColorは所有されないことを知っています。
以下の例で示すように、適切な型キャストを使用する必要があります。

NSMutableArray *colors = [NSMutableArray arrayWithObject:(id)[[UIColor darkGrayColor] CGColor]];
[colors addObject:(id)[[UIColor lightGrayColor] CGColor]];


・所有権キーワードを使用した関数パラメータのキャスト

関数呼び出しでObjective-CとCore Foundationオブジェクト間のキャストをする場合、渡されたオブジェクトの所有権のセマンティクスについてコンパイラに指示する必要があります。
Core Foundationオブジェクトの所有権規則はCore Foundationメモリ管理規則(『Memory Management Programming Guide for Core Foundation』参照)で、Objective-Cオブジェクトの規則は『高度なメモリ管理プログラミングガイド』で指定されています。

以下のコードでは、CGGradientCreateWithColors関数に渡される配列は適切なキャストが必要です。
arrayWithObjects:によって返されたオブジェクトの所有権は関数に渡さないので、キャストは__bridgeです。

NSArray *colors = <#An array of colors#>;
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);

このコードを以下のメソッド実装のコンテキストで示します。
またCore Foundationのメモリ管理規則によって決定される、Core Foundationのメモリ管理関数を使用することが分かります。

- (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を呼び出すことはできません。
    これは特徴です。
    また記述することはできません。
    while ([x retainCount]) { [x release]; }

  • deallocを呼び出すことはできません。
    シングルトンを実装する、またはinitメソッドでオブジェクトを置換する場合は、通常deallocを呼び出します。
    シングルトンの場合は、共有されたインスタンスパターンを使用します。
    initメソッドの場合、自身を上書きした時点でオブジェクトは解放されるので、deallocを呼び出す必要はありません。

  • NSAutoreleasePoolオブジェクトを使用することはできません。
    代わりに新たな@autoreleasepool{}構造を使用します。
    自動解放プールはこのブロック構造に強制されますが、NSAutoreleasePoolよりも約6倍高速です。
    @autoreleasepoolは非ARCコードでも動作します。
    @autoreleasepoolはNSAutoreleasePoolよりも高速なので、多くの古い『性能向上手法』は無条件で@autoreleasepoolに単純に置換することができます。
    移行ツールはNSAutoreleasePoolの使用を簡易に処理しますが、複雑な条件の場合や、新しい@autoreleasepoolの本体内で定義された変数を後で使う場合は処理できません。

  • ARCでのinitメソッドでは、selfへの[super init]の結果を割り当てる必要があります。
    ARCでのinitメソッドでは以下の文は無効になります。
    [super init];
    簡易修正では次のように変更します。
    self = [super init];
    正式な修正では、続行する前に結果がnilであるかをチェックします。
    self = [super init];
    if (self) {
        ...

  • カスタムのretainやreleaseメソッドを実装することはできません。
    カスタムのretainやreleaseメソッドの実装はweakポインタを破壊します。
    カスタム実装を要するにはいくつかの一般的な理由がありますが、対処を示します。
    • 性能。
      これ以上は求めないでください。
      NSObjectのretainやreleaseの実装は現時点でかなり高速です。
      それでもまだ問題が見つかる場合はファイルの欠陥です。
    • カスタムのweakポインタシステムを実装。
      代わりに__weakを使用してください。
    • シングルトンクラスの実装。
      代わりに共有されたインスタンスパターンを使用してください。
      また全くオブジェクトを割り当てる必要が無い場合は、インスタンスメソッドの代わりにクラスを使用します。

  • 『割り当てられた』インスタンス変数はstrongになる。
    ARCの以前はインスタンス変数は非所有変数であり、インスタンス変数にオブジェクトを直接割り当てると、オブジェクトの寿命を延長しませんでした。
    プロパティをstrongにするには、通常適切なメモリ管理メソッドを呼び出して実装するか、アクセサメソッドを合成します。
    対照的にweakプロパティを維持するには、以下の例で示すようにアクセサメソッドを実装します。
    @interface MyClass : Superclass {
        id thing; // Weak reference.
    }
    // ...
    @end

    @implementation MyClass
    - (id)thing {
        return thing;
    }
    - (void)setThing:(id)newThing {
        thing = newThing;
    }
    // ...
    @end
    ARCではインスタンス変数はデフォルトで強い参照であり、インスタンス変数にオブジェクトを直接割り当てると、オブジェクトの寿命を延長します。
    移行ツールは、インスタンス変数がweakと意図されているかを判断することはできません。
    以前と同じ動作を維持するためには、weakとなるようインスタンス変数を印すか、宣言済みプロパティを使用する必要があります。
    @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

  • C構造体内でstrongのidを使用することはできません。
    例えば以下のコードはコンパイルされません。
    struct X { id x; float y; };
    これはxはデフォルトで強く保持され、コンパイラは安全に正常に動作するために必要な全てのコードを合成することができないためです。
    例えば、最後にはfreeをすることになるいくつかのコードを介してこれらの構造体のいずれかにポインタを渡す場合、各idはstructが解放される前に解放する必要があります。
    コンパイラは確実にこれを行うことができず、構造体内の強いidはARCモードで完全に却下されます。
    これにはいくつかの可能な解決方法があります。
    1. 構造体の代わりにObjective-Cオブジェクトを使用する。
      これはいずれの場合でも最善慣行であると考えられます。
    2. Objective-Cオブジェクトの使用が次善である場合、(おそらくこれらの構造体を密接に配置したい場合は)代わりにvoid*を使用することを検討してください。
      この場合後述するように明示的なキャストの使用が必要となります。
    3. __unsafe_unretainedとしてオブジェクトの参照を印す。
      このアプローチは以下のような半共通パターンで役立つでしょう。
      struct x { NSString *S; int X; } StaticArray[] = {
          @"foo", 42,
          @"bar, 97,
      ...
      };
      構造体は次のように宣言します。
      struct x { NSString * __unsafe_unretained S; int X; }
      これはオブジェクトがポインタ下から解放される場合があるという問題をはらんでいて危険ですが、不変の文字列リテラルのように常に存在するものと知られている場合は非常に便利です。

  • idと(Core Foundation型を含む)void *間で直接キャストを行うことはできません。
    詳細は『Toll-Free Bridgingの管理』を参照してください。



●よくある質問


・ARCについてどう考えればいいのですか?どこにretain/releaseを置くのですか?

retain/releaseの呼び出しをどこに置くかについて考えるのは止めて、代わりにアプリケーションのアルゴリズムを考えてください。
オブジェクトの"strongとweak"ポインタや、オブジェクトの所有権、そして有効な保持循環について考えてください。


・自分のオブジェクトのためにdeallocメソッドを記述する必要はまだありますか?

おそらく。

ARCはmalloc/free、Core Foundationオブジェクトの寿命の管理、ファイル記述子などを自動化しておらず、そのようなリソースは依然としてdeallocメソッドを記述することによって解放します。

インスタンス変数を解放する必要はありません(実際にはできません)が、ARCを使用してコンパイルしていない他のコードやシステムクラス上で[self setDelegate:nil]を呼び出す必要があるかもしれません。

ARCでのdeallocメソッドは[super dealloc];の呼び出しを必要と(または許可)せず、superへのチェーニングはランタイムによって適用と処理がなされます。


・保持循環はARCでもまだ可能ですか?

はい。

ARCはretain/releaseを自動化し、保持循環の問題を継承します。
幸いなことにARCへ移行したコードでは、プロパティは保持されているかどうかが既に宣言されているため、リークすることは稀です。


・ARCではブロックはどのように動作するのですか?

ARCモードで戻り値などとしてブロックをスタックに渡すと、ブロックは"正確に動作"します。
もうブロックのコピーを呼び出す必要はありません。
arrayWithObjects:内のスタックに"down"を渡し、他のメソッドが保持しない場合は、まだ[^{} copy]を使用する必要があります。

一つ注意すべき点は、NSString * __block myStringはARCモードでは保持され、ダングリングポインタにはならないことです。
以前の動作を取得するには、__block NSString * __unsafe_unretained myStringを使用するか、または(より良い)__block NSString * __weak myStringを使用してください。


・Snow Leopard上で、ARCを使用したOS X用のアプリケーションを開発することはできますか?

いいえ。
Snow LeopardのバージョンであるXcode 4.2は10.7 SDKを含んでいないため、OS X上の全てでARCをサポートしていません。
Snow Leopard用のXcode 4.2はiOS用のARCはサポートしており、Lion用Xcode 4.2はOS XとiOSの両方をサポートします。
これはSnow Leopard上で実行するARCアプリケーションを構築するには、Lionのシステムが必要だということを意味します。


・ARC下で保持されたポインタのC配列を生成することはできますか?

はい、以下の例に示すように生成することができます。

// 注:calloc()でゼロで初期化されたメモリを取得します。
__strong SomeClass **dynamicArray = (__strong SomeClass **)calloc(sizeof(SomeClass *), entries);
for (int i = 0; i < entries; i++) {
    dynamicArray[i] = [[SomeClass alloc] init];
}

// 完了したら、オブジェクトの解放をARCに伝えるために各エントリをnilに設定します。
for (int i = 0; i < entries; i++) {
    dynamicArray[i] = nil;
}
free(dynamicArray);

注意する点がいくつかあります。
  • いくつかの場合デフォルトでは__autoreleasing SomeClass **になっているため、__strong SomeClass **と記述する必要があります。

  • 割り当てるメモリはゼロで初期化する必要があります。

  • 配列を解放する前に各要素をnilに設定する必要があります(memsetやbzeroは動作しません)。

  • memcpyやreallocは避ける必要があります。


・ARCは遅い?

貴方が何を測定するかに依りますが、一般的には"ノー"です。
コンパイラは効率的に多くの無駄なretain/release呼び出しを排除し、一般的なObjective-Cのランタイムの高速化に多くの努力を注いでいます。
特に一般的な"保持/自動解放されたオブジェクトを返す"パターンは遥かに高速であり、メソッドの呼び出し元がARCコードの場合は実際には自動解放プールにオブジェクトを入れていません。

一つ注意すべき問題は、通常のデバッグ攻勢ではオプティマイザが実行されないことで、-Osの時より-O0の時により多くのretain/releaseトラフィックが観測されることを予期してください。


・ObjC++モードでARCは動作しますか?

はい。
クラスやコンテナにstrong/weakのidを置くこともできます。
ARCコンパイラはこの処理を行うために、コンストラクタとデストラクタのコピーにretain/releaseロジックを合成します。


・弱い参照をサポートしていないクラスはどれですか?

以下のクラスのインスタンスには、現在弱い参照を作成することはできません。

NSATSTypesetter、NSColorSpace、NSFont、NSMenuView、NSParagraphStyle、NSSimpleHorizontalTypesetter、そしてNSTextViewです。

:また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のインスタンスから弱い参照を作成することができません。


・NSCopyObjectを使用するNSCellまたは他のクラスをサブクラス化する場合に何かすべきことはありますか?

特別にすることはありません。
ARCは以前に追加されていた明示的に保持する必要があるものも面倒をみます。
ARCでは、全てのcopyメソッドはインスタンス変数を単に上書きコピーする必要があります。


・特定のファイルをARCから除外することはできますか?

はい。

ARCを使用するようにプロジェクトを移行する場合、-fobjc-arcコンパイラフラグを全てのObjective-Cのソースファイルのデフォルトとして設定します。
特定のクラスに-fno-objc-arcコンパイラフラグを使用することで、そクラスのARCを無効にすることができます。
Xcodeでソースファイルリストを開示するために、TARGETのBuild PhasesタブでCompile Sourcesグループを開きます。
フラグを設定したいファイルをダブルクリックし、ポップアップパネル内に-fno-objc-arcと入力し、Doneボタンをクリックします。

fno-objc-arc.png


・Mac上ではGC(ガベージコレクション)は非推奨ですか?

ガベージコレクションはOS X Moutain Lion v10.8で非推奨となり、将来のOS Xのバージョンで削除されます。
自動参照カウントは推奨される置換技術です。
既存アプリケーションの移行の援助するものとして、Xcode 4.3以降のARC移行ツールが、ガベージコレクションを利用しているOS XアプリケーションのARCへの移行をサポートします。

:Mac App Storeをターゲットにしているアプリの場合、Mac App Storeガイドライン(『App Store Review Guidelines for Mac Apps』参照)では非推奨の技術の使用を禁止しているため、可及的速やかにARCでガベージコレクションを置換することを強く推奨します。



参考文献

Apple/Transitioning to ARC Release Notes

0 CommentsPosted in 資料





Bose SoundSport wireless headphones
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
02 | 2017/03 | 03
Sun Mon Tue Wed Thu Fri Sat
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 -
Recent Articles
iTunes


Swift
Categories
Tips
WACOM


Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
BOSE

Bose SoundSport wireless headphones
ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
SQLite
OpenGL ES
Amazon


Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Profile

Author:水月杏香
永遠の初心者プログラマ。

QR Code
QR
Visitors