2

他の場所で答えが見つからない問題に出くわしました。後で使用され、最後に nil に設定されたオブジェクトへのポインターを返すメソッドを呼び出している場合、それはまだメモリに割り当てられています (Instruments によると)。XCode 4.6.3 と iOS 6.1 を使用しています。ARC がオンになっています。

サンプルコードは次のとおりです。

ClassA.h

@interface ClassA : NSObject
    -(void)runSomething;
@end

ClassA.m

#import "ClassA.h"
#import "ClassB.h"

@implementation ClassA

-(void)runSomething {
    int counter = 0;
    while (true) {
        ClassB *instance = [self makeClassBWithNumber:counter];
        NSLog(@"%d", [instance getNumber]);
        [NSThread sleepForTimeInterval:0.01];
        instance = nil;
        counter++;
    }
}

-(ClassB*) makeClassBWithNumber:(int)number {
    return [[ClassB alloc] initWithNumber:number];
}

@end

ClassB.h

@interface ClassB : NSObject
@property int number;
    -(id)initWithNumber:(int)number;
    -(int)getNumber;
@end

ClassB.m

#import "ClassB.h"

@implementation ClassB

-(id)initWithNumber:(int)number {
    self = [super init];
    if(self) {
        _number = number;
    }
    return self;
}

-(int)getNumber {
    return [self number];
}

@end

View ControllerにClassBを作成し、runSomethingメソッドを呼び出します。このサンプル コードでは、作成されたオブジェクト (ClassB) がメモリから解放されることはありません。コードを変更すると

ClassB *instance = [self makeClassBWithNumber:counter];

ClassB *instance = [[ClassB alloc] initWithNumber:counter];

作成されたオブジェクトは、各ループ サイクルで適切に解放されます。そのような行動の理由は何ですか?makeClassBWithNumberここで、 autorelease を呼び出す結果を返すはずの古い回答がいくつか見つかりましたreturn [result autorelease]が、ARCが有効になっている場合、これは実行できません。

4

4 に答える 4

5

makeClassBWithNumberARC を使用しても、自動解放されたオブジェクトを返します。(より正確には、最適化に応じて、自動解放されたオブジェクトを返すことができます。)

手動の参照カウントとの違いは、ユーザーではなく、ARC コンパイラが必要に応じて autorelease 呼び出しを挿入することです。

Clang/ARCドキュメントから:

3.2.3 保持されない戻り値

保持可能なオブジェクト型を返すが、保持された値を返さないメソッドまたは関数は、戻り境界を越えてオブジェクトがまだ有効であることを保証する必要があります。

そのような関数またはメソッドから戻るとき、ARC は return ステートメントの評価の時点で値を保持し、次にすべてのローカル スコープを離れて、値が呼び出しの境界を越えて存在することを保証しながら、保持のバランスを取ります。 最悪の場合、これには autorelease が含まれる可能性がありますが、呼び出し元は値が実際に autorelease プールにあると想定してはなりません。

makeClassBWithNumberalloc、copy、init、mutableCopy、または new メソッドではないため、保持されない戻り値を返します。

于 2013-09-10T19:46:58.257 に答える
5
于 2013-09-10T19:47:12.617 に答える
1

他の人が言っているように、あなたが見ている違いは、メソッドが返され、呼び出し元が所有するオブジェクトか、呼び出し元が所有していないオブジェクトかによって異なります。

前者のカテゴリには、、、、およびallocカテゴリのメソッドがあります。これらはすべて呼び出し元が所有するオブジェクトを返し、ARC はそれが確実に解放されるようにします。initnewcopymutableCopy

後者のカテゴリには、最初のカテゴリにないすべてのメソッドがあります。これらは、呼び出し元が所有していないオブジェクトを返します。ARC は、必要に応じてこのオブジェクトが保持され、保持されている場合は解放されることを保証します。このカテゴリの戻り値は、自動解放プールにある可能性があります。つまり、少なくともプールにある限り (ARC によって保持されている場合はそれより長くなる可能性があります)、標準プールは最後に空になります。各実行ループサイクルの。これは、自動解放プールに多くのエントリを生成するループで、不要になった多くのオブジェクトがプールに蓄積される可能性があることを意味します。これが表示されていることです。

MRC での解決策は、そのようなループ内にローカルの自動解放プールを導入して、不要になったオブジェクトの蓄積を回避することでした。ただし、ARC では、これはおそらく最良の選択ではありません。

ARC では、より良い解決策はおそらく命名規則に従うことです。この場合、newパターン -を使用することをお勧めします。これは、1 つのメソッドでの+newの標準パターンです。したがって、名前を次のように変更します。allocinitmakeClassBWithNumbernewClassBWithNumber

// *create* a new ClassB object
- (ClassB *) newClassBWithNumber:(int)number
{
   return [[ClassB alloc] initWithNumber:number];
}

これは、メソッドが呼び出し元が所有するオブジェクトを返すことを示します。これは「作成」メソッドであり、ARC はオブジェクトを蓄積しなくても残りを処理します。

newWithNumber(メソッドをそれ自体に追加するClassBことは、多くの場合、ARC では良い考えです。)

于 2013-09-10T20:30:34.653 に答える
1

あなたの質問の有効な言葉は「OLD」です。古い回答はもはや関係ありません。

これがARCの目的です。

メモリ管理について心配する必要はもうありません。

ARCがそれをしないように言ったら... しないでください。

この場合、autorelease は必要ありません。

于 2013-09-10T19:45:06.160 に答える