arc of developer part1
TRANSCRIPT
ARC of a Developer Part.1
11年11月22日火曜日
Automatic Referrence Counting
• Objective-Cのための新しい自動メモリ管理
• 生産性の向上 - タイプ数が少ないからね
• メンテナンス性の向上 - retain、releaseを考えなくても良くなるからね
• 安全で安定 - weak修飾子で安全なweak referrenceができるからね
11年11月22日火曜日
メモリ管理、マジ大変
• 手動でメモリを管理するのは熟練が必要
• すでに死んだオブジェクトへのアクセス
• EXC_BAD_ACCESS ヒャッハー!
• 2重にreleaseしちゃう
• NSZombie最高
• 循環参照でリーク
• 宙ぶらりんになったポインタ
11年11月22日火曜日
ARCはパフォーマンスを改善する
• GCじゃないから、オブジェクトグラフをスキャンする必要はない
• パフォーマンス
• retain/releaseが2.5倍速くなる
• autoreleasepoolが6倍速くなる
• objc_msgSendが33%速くなる
11年11月22日火曜日
ARCを有効にするには?
• 新しいプロジェクトを作るなら
11年11月22日火曜日
ARCを有効にするには?
• 既存のプロジェクトをARCにマイグレーションするなら
• LLVM3.0を使用する
• コンパイラオプション 「-fobjc-arc」を指定する
11年11月22日火曜日
ファイルごとに無効にするには?
• ファイルごとに、「-fno-objc-arc」を指定する
11年11月22日火曜日
実行環境の制約
• iOS4ではweak referenceは使えない
• __unsafe_unretained を使う
• weak reference以外は動くよ!
11年11月22日火曜日
所有修飾子
• __strong
• __weak
• __unsafe_unretained
• __autoreleasing
• こんだけ増えるよ!
11年11月22日火曜日
Before ARC
• 参照カウント
• 戻り値はautorelease
• 手動でメモリの管理をする
11年11月22日火曜日
参照カウント方式のメモリ管理
• オブジェクトをいつ破棄するか管理する一つの手法
• VB6
• COM
• Objective-C
• スマートポインタ
• JAVA、.NETはガベージコレクション Obj-CでもGCあるよ
11年11月22日火曜日
参照カウント方式、どういう仕組?
• NSObject *obj = [[NSObject alloc]init];
NSObject
1
* obj
11年11月22日火曜日
参照カウント方式、どういう仕組?
• NSObject *obj = [[NSObject alloc]init];
• NSObject *obj2 = [obj retain];
NSObject
2
* obj
* obj2
11年11月22日火曜日
参照カウント方式、どういう仕組?
• NSObject *obj = [[NSObject alloc]init];
• NSObject *obj2 = [obj retain];
• [obj release];
NSObject
1* obj2
11年11月22日火曜日
参照カウント方式、どういう仕組?
• NSObject *obj = [[NSObject alloc]init];
• NSObject *obj2 = [obj retain];
• [obj release];
• [obj2 release]; NSObject
0破棄!
11年11月22日火曜日
Autorelease
• 主にメソッドの戻り値で使う
+(id)array{ NSMutableArray *array = [[[NSMutableArray alloc]init]autorelease]; return array;}
* array
NSArray
1
11年11月22日火曜日
Autorelease
• 主にメソッドの戻り値で使う
+(id)array{ NSMutableArray *array = [[[NSMutableArray alloc]init]autorelease]; return array;}
* array
NSArray
1autorelease pool
あとでreleaseしとくわ
11年11月22日火曜日
Autorelease
• 主にメソッドの戻り値で使う
+(id)array{ NSMutableArray *array = [[[NSMutableArray alloc]init]autorelease]; return array;}
NSArray
1あとでreleaseしとくわautorelease pool
11年11月22日火曜日
Autorelease
• 主にメソッドの戻り値で使う
+(id)array{ NSMutableArray *array = [[[NSMutableArray alloc]init]autorelease]; return array;}
NSArray
0破棄!
11年11月22日火曜日
Retain Release Autorerelease
• ちゃんと寿命をわかってかかないといかん
• ちょっとしたミスで致命的なバグを作り込む
11年11月22日火曜日
リークしてる?
11年11月22日火曜日
リークする
• 相当に注意深くないとリークする
• リークが実用的な範囲に収まってればいいけどね
11年11月22日火曜日
Xcode Static Analyzer
• XcodeからAnalyze
• 静的にある程度リークや不正なポインタがないか調べてくれる
11年11月22日火曜日
そこでARC
• わりと寿命を意識しなくてもよくなる
• じぶんでRetainとかReleaseとか書かない
11年11月22日火曜日
所有修飾子
• __strong
• __weak
• __unsafe_unretained
• __autoreleasing
11年11月22日火曜日
nilで初期化されるよ
• 修飾子がついた変数はnilで初期化されるので安全!
• id __strong obj1;
• id __strong obj1 = nil;
11年11月22日火曜日
__strong
• そのポインタがオブジェクトを所有するときに使う
• id型とオブジェクト型にデフォルトで付与される
• id test = [[NSObject alloc]init];
• id __strong test = [[NSObject alloc]init];
• もうretain releaseは各必要がないよ
• ポインタを見たらたいていはstrongだと思え!
11年11月22日火曜日
__strong
• deallocでのreleaseは必要なくなる
• 自動的にインスタンス変数は破棄されるので、releaseはいらない
• ポインタにオブジェクトを代入すると自動でRetainするイメージ
• スコープが終わると自動でReleaseされるイメージ
11年11月22日火曜日
__strong
• arrayにオブジェクトが代入されたら+1されてる
• スコープを抜けたらarrayは破棄されるので、-1されて 破棄される
{ NSMutableArray *array = [[NSMutableArray alloc]init]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]];}
これは + 1されない!ここで+1
11年11月22日火曜日
従来のRetainのプロパティに近い
@property (nonatomic,retain) NSMutableArray *array;
{ self.array = [[[NSMutableArray alloc]init]autorelease]; [array addObject:[[[NSObject alloc]init]autorelease]]; [array addObject:[[[NSObject alloc]init]autorelease]]; [array addObject:[[[NSObject alloc]init]autorelease]]; [array addObject:[[[NSObject alloc]init]autorelease]];}
{ NSMutableArray *array = [[NSMutableArray alloc]init]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]];}
11年11月22日火曜日
違うのは実際にはAutoreleaseプールに入らない
• Relaseが呼び出される回数が違う
{ NSMutableArray *array = [[NSMutableArray alloc]init]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]]; [array addObject:[[NSObject alloc]init]];}
これは + 1されない!ここで+1
11年11月22日火曜日
戻り値はどうすんの?
• 今まではautoreleaseして返してた
• これからはコンパイラが戻り値かどうかを判定して自動的にautorelease poolに突っ込んでくれます
+(id)array{ id obj = [[NSMutableArray alloc]init]; return obj;}
11年11月22日火曜日
プロパティはどうかな?
assign __unsafe_unretained
copy __strong
retain __strong
strong __strong
unsafe_unretained __unsafe_unretained
weak __weak
11年11月22日火曜日
strong最高じゃん!
• もうreleaseもretainもいらない!
• というか、コンパイルエラーになるからね
11年11月22日火曜日
いやそうでもない
循環参照
11年11月22日火曜日
循環参照って?
• パッと見ではわからないリーク
A
B C
DE
11年11月22日火曜日
循環参照って?
A
B C
DE
11年11月22日火曜日
循環参照
A
B C
DEassign
11年11月22日火曜日
どんなコードで循環参照が起こるか@interface Test : NSObject{ id childObject;}-(void)setObject:(id)child;
@end
{ id test1 = [[Test alloc]init]; id test2 = [[Test alloc]init]; [test1 setObject:test2]; [test2 setObject:test1];}
11年11月22日火曜日
適当な図で書くと・・・
test1 test2
test1 test2
{ id test1 = [[Test alloc]init]; id test2 = [[Test alloc]init]; [test1 setObject:test2]; [test2 setObject:test1];}
11年11月22日火曜日
__weak
@interface Test : NSObject{ id __weak childObject;}-(void)setObject:(id)child;
@end
test1 test2
• Retainされないポインタだと思ったらいい
11年11月22日火曜日
__weakのとても素晴らしい機能
• 参照先のオブジェクトが破棄されると自動的にnilが代入される
• 死んだオブジェクトへの参照が発生しない
test1 test2
11年11月22日火曜日
__weak
• 循環参照になるときとか、delegateみたいに所有しないものにつける?
id __weak obj = [[NSObject alloc]init];
これは + 1されない!
11年11月22日火曜日
autorelease pool
• 短い時間使うオブジェクトをさっくりと破棄する場合
• 自分で新しいThreadを起動した場合
• LLVM3.0以降ならARC無効でも使えるよ
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; // ほにゃほにゃ [pool drain];
@autoreleasepool { // ほにゃほにゃ }
11年11月22日火曜日
トールフリーブリッジ
• ひぃ!
11年11月22日火曜日
ナイス書籍
達人出版会で買えるよ
11年11月22日火曜日