Autoreleaseのオブジェクト

2899 ワード

まず、古典的なパフォーマンスの問題を見てみましょう。

for (int i = 0; i <= 1000; i ++) {
     UIImage *image = [UIImage imageNamed:@"test"];
    //Do something...
}

C言語のローカル変数の定義によると、imageは役割ドメインを超えて解放されますが、テスト中にメモリが増加していることに気づきました.これはなぜですか.

解析:


[UIIMage imageName:]作成されたオブジェクトはAutoreleaseで、Autoreleaseのオブジェクトは最近のAutoreleasePoolに追加され、AutoreleasePoolが終了すると一括して解放されます.

では、Autoreleaseとは何ですか?


Autoreleaseとは何かを知りたい場合は、MRCのretain、releaseメカニズムを振り返ってみましょう.retainは保持オブジェクトを表し、releaseは解放オブジェクトを表す.
次の名前で始まるメソッド名は、自分が生成したオブジェクトが自分で持っていることを意味します.
  • alloc
  • new
  • copy
  • mutableCopy
  • id obj = [[NSObject alloc] init];// 
    [obj release];// 
    

    以上の4つの方法で作成されたオブジェクトを除いて、自分が持っているものではありません.
    id obj = [NSMutableArray array];// 
    [obj retain]; // 
    [obj release]; // 
    

    arrayの実装を見てみましょう.
    + (id)array {
        id obj = [[NSMutableArray alloc] init];// 
        [obj autorelease];// ( )
        return obj;
    }
    
    [NSMutableArray array]を使用してオブジェクトを作成する場合は、オブジェクト自体を持っていないので、またオブジェクトの存在を取得したい.Autoreleaseは、指定された生存範囲を超えたときにオブジェクトが自動的に正しく解放されるようにする機能を提供します.
    Autoreleaseは実際にはreleaseの呼び出しを遅らせただけで、各Autoreleaseに対して、システムは現在のAutoreleasePoolにObjectを入れただけで、poolが解放されると、poolのすべてのObjectがReleaseを呼び出す.Runloopごとに、AutoreleasePoolが暗黙的に作成されます.これにより、すべてのrelease poolがCallStackのようなスタック構造を構成し、各Runloopが終了すると、現在のスタックトップのAutoreleasePoolが破棄され、このpoolの各Objectがreleaseされます.

    では、作成したオブジェクトがAutoreleaseであるかどうかをどのように判断しますか?


    alloc/new/copy/mutableCopyを使用するオブジェクトはAutoreleaseではなく、以上の方法で作成されていないオブジェクトはAutoreleaseです.
    具体的には、次の方法でテストできます.
    __weak id reference = nil;
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSString *str = [NSString stringWithFormat:@"xhj"];
        // str autorelease , weak 
        reference = str;
    }
    
    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        NSLog(@"%@", reference);// Console: xhj
    }
    
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        NSLog(@"%@", reference);//Console:nil
    }
    

    referenceがviewWillApper:メソッドでまだ解放されていない場合は、Autoreleaseのオブジェクトを表します.

    文章の冒頭の問題の解決

    for (int i = 0; i <= 1000; i ++) {
        @autoreleasepool {
            UIImage *image = [UIImage imageNamed:@"test"];
            //Do something...
        }
    }
    

    ループのたびにイメージオブジェクトが自動的に解放されます.
    または、
    [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        //  @autoreleasepool 
        UIImage *image = [UIImage imageNamed:@"test"];
        //Do something...
    }];
    

    コンテナのblockバージョンの列挙器を使用すると、内部にAutoreleasePoolが自動的に追加されます.

    参照ドキュメント:


    「Objective-C高度プログラミングiOSとOS Xマルチスレッドとメモリ管理」の黒幕の背後にあるAutorelease@autoreleasepool-メモリの割り当てと解放