ARCとは?ios5,xcode 4.2


ARCって何?


ARCはiOS 5の新機能で、ARC(Automatic Reference Counting)と呼ばれています.簡単に言えば、コードにretain/releaseが自動的に追加され、メモリ管理の参照カウントを処理するために手動で追加する必要があったコードがコンパイラによって自動的に完了する.
この機能はiOS 5/Mac OS X 10.7から導入され、Xcode 4を利用する.2この機能を使用することができます.ARCを簡単に理解すると、指定された構文により、コンパイラ(LLVM 3.0)がコードをコンパイルする際に、インスタンスの参照カウント管理部分コードを自動的に生成するようにすることである.一つ、ARCはGCではなく、コード静的解析(Static Analyzer)ツールにすぎない.

へんかてん


小さなコードで、ARCを使用する前後の変化点を見てみましょう.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@interface NonARCObject : NSObject {
    NSString *name;
}
-(id)initWithName:(NSString *)name;
@end

@implementation NonARCObject
-(id)initWithName:(NSString *)newName {
    self = [super init];
    if (self) {
        name = [newName retain];
    }
    return self;
}

-(void)dealloc {
    [name release];
    [Super dealloc];
}
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@interface ARCObject : NSObject {
    NSString *name;
}
-(id)initWithName:(NSString *)name;
@end

@implementation ARCObject
-(id)initWithName:(NSString *)newName {
    self = [super init];
    if (self) {
        name = newName;
    }
    return self;
}
@end

以前、Objective-Cのメモリ管理ルールを使用していた場合、次のガイドラインが採用されていました.
オブジェクトの生成時にautorelease を使用
オブジェクト代入の場合、autoreleaseの後にretain オブジェクトが関数で返される場合はreturn[[object retain]autorelease]を使用します.
ARCを使用すると、最も基本的なreleaseさえ必要としなくてもいいです.

ARCを使うメリット


ARCを使うメリットは何ですか?
上記の例を見ると、Objective-Cのコードを書くのは簡単になります.煩わしいメモリ管理を心配する必要はありません.メモリが漏れているのではないかと心配しています.
コードの総量が少なくなり、さわやかに見え、労働力も節約できました.
コードの高速化により、コンパイラで参照カウントを管理することにより、非効率コードの可能性が低減する.

悪いところ


新しいARCルールを覚えておく-キーワードや特性など、一定の学習サイクルが必要いくつかの古いコードは、サードパーティのコードが使用されるときに面倒です.コードを修正するには工数が必要であるか、コンパイルスイッチを修正するか
第2点については、XCode 4.2ではデフォルトARCがONの状態なので、古いコードをコンパイルする際に「Automatic Reference Counting Issue」というエラーメッセージがよくあります.
このとき、プロジェクトコンパイル設定の「Objectice-C Auto Reference Counteting」をNOにすることができます.以下に示す.
誰かにだけmファイルはARCに適応せず、このクラスファイルに対して-fno-objc-arcを加えてFLAGSをコンパイルするだけで、以下の図に示す.

ARC基本ルール


retain,release,autorelease,deallocはコンパイラによって自動的に挿入され、コードでを呼び出すことはできません.
deallocはリロード可能であるが[super dealloc]を呼び出すことはできない.
ARCはGCではなく、コンパイラがコード挿入をサポートするルールが必要であるため、これらのルールを明確にしてから、丈夫なコードを書く必要があります.

Objective-Cオブジェクト


Objectivecのオブジェクトには、強い参照(Strong reference)と弱い参照(Weak reference)の区別があり、他のオブジェクトを保持する必要がある場合は、オブジェクト参照カウントに1を加算するようにretainが必要です.オブジェクトの所有者(owner)が存在する限り、そのオブジェクトの強い参照は常に存在する.
オブジェクト処理の基本ルールは
オブジェクトの所有者が存在する限り(オブジェクトが強く参照される)、そのオブジェクトを使用することができる.
対象が持ち主を失った後、を破棄する.
強参照(Strong reference)
(s1)
FirstNameは、「natsu」文字列オブジェクトの最初の所有者として、NSStringタイプオブジェクトのStrong referenceです.
(s2)
ここではfirstNameをaNameに代入し、すなわちaNameも@"natsu"文字列オブジェクトの所有者となり、そのオブジェクトに対してaNameもStrong referenceとなる.
(s3)
ここで、firstNameの内容を変更します.新しい文字列オブジェクト「maki」を生成します.このときfirstNameは「maki」の持ち主となり、@「natsu」の持ち主はaNameのみとなる.各文字列オブジェクトにはそれぞれの所有者がいるので、メモリに存在します.
(s4)
@makiオブジェクトの別の所有者になる新しい変数otherNameを追加します.つまりNSStringタイプオブジェクトのStrong referenceです.
(s5)
aNameにotherNameを代入すると、aNameは@"maki"文字列オブジェクトの所有者になります.相手@"natsu"は既に持ち主がいなくなり、その対象は破棄される.
弱参照(Weak reference)
次に弱参照(Weak reference)の使い方を見てみましょう.
(w1)
強参照方式と同様にfirstNameは文字列オブジェクト@"natsu"の持ち主として存在する.つまり、NSStringタイプのオブジェクトのStrong referenceです.
(w2)
キーワード_を使用Weak、弱参照weakName変数を宣言し、firstNameを代入します.このときweakNameは@"natsu"を参照するが、Weak referenceである.つまりweakNameは@"natsu"が見えるが、その持ち主ではない.
(w3)
FirstNameは新しいオブジェクト@「maki」を指し、その所有者となり、オブジェクト@「natsu」は所有者がいないため、破棄される.同時にweakName変数はnilに自動的に代入されます.

参照キー


ARCにおけるオブジェクトに関する参照には,主に次のキーワードがある.strong,weak,autoreleasingで定義された変数は暗黙的にnilに初期化されます.
__strong
変数宣言のデフォルトには__があります.strongキーワードは、変数がキーワードを何も書かない場合、デフォルトは強い参照です.
__weak
上にも見えますが、これは弱参照のキーワードです.この概念は新しい特性であり,iOS 5/Mac OS X 10.7から導入される.このタイプはオブジェクトのライフサイクルに影響を与えないため、オブジェクトの前に所有者がいない場合、作成したばかりで破棄される問題が発生します.たとえば、次のコードです.
1
2
NSString __weak *string = [[NSString alloc] initWithFormat:@"First Name: %@", [self firstName]];
NSLog(@"string: %@", string); //  string 

コンパイル設定OSバージョンDeployment Targetがこれよりも低いバージョンに設定されている場合、コンパイル時にエラー(The current deployment target does not support automated__weakreferences)が報告されますが、この場合は下記の_unsafe_unretained.
弱い参照には、パラメータオブジェクトが所有者を失うと、変数が自動的にnil(Zeroing)に付けられるという特徴もあります.
__unsafe_unretained
キーワードと_weak同様、弱参照であり、_Weakの違いはnil付与(Zeroing)を実行するかどうかだけです.ただし,変数が指すオブジェクトは破棄され,アドレスはまだ存在するが,メモリにはオブジェクトが存在しないことに注意する必要がある.このオブジェクトにアクセスすると、「BAD_ACCESS」エラーが発生します.
__autoreleasing
このキーワードは、対像遅延を解放する.たとえば、初期化されていない対像をメソッドに参照し、このメソッドで対像をインスタンス化したい場合は、__を使用します.autoreleasing.彼は、次の例のように、関数の値パラメータが返されるときの処理によく使用されます.
1
2
3
4
5
6
7
8
9
10
11
- (void) generateErrorInVariable:(__autoreleasing NSError **)paramError {
    ....
    *paramError = [[NSError alloc] initWithDomain:@"MyApp" code:1 userInfo:errorDictionary];
}

....
{
    NSError *error = nil;
    [self generateErrorInVariable:&error];
    NSLog(@"Error = %@", error);
}

また、関数の戻り値が関数で申請されている場合、解放を望むのは呼び出し側であり、次のコードがあることが多い.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-(NSString *)stringTest
{
    NSString *retStr = [NSString stringWithString:@"test"];

    return [[retStr retain] autorelease];
}

//  ARC

-(NSString *)stringTest
{
    __autoreleasing NSString *retStr = [NSString alloc] initWithString:@"test"];

    return retStr;
}

すなわち、メソッドのパラメータがid*であり、メソッドが返されることを望む場合、オブジェクトがautoreleasedされると、このキーワードが使用される.

まとめ


今日、基本的なARCの使用ルールを見ました.
コードにはretain,release,retain,autorelease は使用できません.
deallocを再ロードしない(オブジェクトメモリを解放する以外の処理であれば、この関数を再ロードできますが、[super dealloc]を呼び出すことはできません).
NSAllocateObject、NSDellocateObject は使用できません.
オブジェクトポインタはC構造体では使用できない.
idとvoid*の間のcastの場合は特定のメソッド(_bridgeキーワード)が必要である.
NSAutoReleasePoolは使用できませんが、@autoreleasepoolブロックが必要です.
「new」から始まる属性名は使用できません(次のコンパイルエラーがある場合は「Property」s synthesized getter follows Cocoa nameing convention for returning「owned」objects」).
今後はさらにARCに深く入り込み、より多くの特性を学びます.