ARC和在方法中创建的释放对象 [英] ARC and releasing object created in method

查看:188
本文介绍了ARC和在方法中创建的释放对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我偶然发现了一个在其他地方找不到答案的问题.当我调用一个返回指向对象的指针的方法时,该对象后来被使用并且最后设置为nil,它仍然在内存中分配(根据Instruments).我正在使用XCode 4.6.3和iOS 6.1. ARC已打开.

I have stumbled upon an issue for which I can't find answer elsewhere. When I am calling a method which returns pointer to an object which is later used and at the end set to nil, it is still allocated in memory (according to Instruments). I'm using XCode 4.6.3 and iOS 6.1. ARC is turned on.

这是示例代码:

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

在视图控制器中创建ClassB,并调用runSomething方法.此示例代码生成了从未从内存中释放创建的对象(ClassB).如果我从

ClassB is created in view controller and method runSomething is called. This sample code produces that created object (ClassB) is never released from memory. If I change code from

ClassB *instance = [self makeClassBWithNumber:counter];

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

创建的对象会在每个循环周期中正确释放.这种行为的原因是什么?我在stackoverflow上发现了一些旧的答案,即makeClassBWithNumber应该返回调用自动释放return [result autorelease]的结果,但是如果启用了ARC,则无法做到这一点.

created object is properly released in each of loop cycle. What is the reason for such behaviour? I found some old answers here on stackoverflow that makeClassBWithNumber should return result invoking autorelease return [result autorelease], but this can't be done if ARC is enabled.

推荐答案

区别在于+alloc返回具有+1保留的对象,ARC将在其作用域末尾与发布保持平衡,因此立即解除分配. +make…返回具有+1保留和匹配的自动释放的对象.自动释放池耗尽后将发送release消息.由于您处于"true时"循环,因此自动释放池永远不会耗尽,并且会累积内存.

The difference is that +alloc returns an object with a +1 retain, which ARC will balance with a release at the end of its scope, and so immediately deallocate. +make… returns an object with a +1 retain and a matching autorelease. The autorelease pool will send a release message when it drains. Since you stay in loop "while true," the autorelease pool never drains and you accumulate memory.

解决方案是为您的循环提供一个自动释放池:

The solution is to give your loop an autorelease pool:

while (true) {
    @autoreleasepool { // <== Add an autorelease block here.
      ClassB *instance = [self makeClassBWithNumber:counter];
      //NSLog(@"%d", [instance getNumber]);
      NSLog(@"%d", [instance number]); // Fix naming; do not prefix accessors with `get`
      [NSThread sleepForTimeInterval:0.01];
      // instance = nil; // Does nothing in this loop.
      counter++;
    }
}

这将导致池在每次迭代中耗尽.在任何情况下,instance=nil都是不必要的.

This will cause the pool to drain on every iteration. In any case the instance=nil is unnecessary.

请务必阅读MartinR的答案.它提供了有关实现细节的更多详细信息,尤其是为什么它可能会根据优化级别而有所不同,以及被调用方法是否与调用方法位于同一编译单元(.m文件)中.那只是一个优化细节;您仍然需要将此@autoreleasepool放入循环中以确保正确性.

Do read MartinR's answer. It gives some more details on the implementation details, and particularly why this may behave differently depending on the optimization level, and whether the called method is in the same compile unit (.m file) as the calling method. That is only an optimization detail; you still need to put this @autoreleasepool in the loop for correctness.

这篇关于ARC和在方法中创建的释放对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆