移除物体时内存不释放 - 不清楚在ARC中正确释放的方式

时间:2014-06-29 14:49:28

标签: ios objective-c

Xcode 5,iOS7

我有一个应用程序,它在循环中创建UILabel,在数组中引用它们。 在反复呼叫“创造”之后方法I注意到我的内存使用量增加了。 我想清除数组和相关的UILabel对象以释放内存, 因为看起来我的当前代码没有发生。相反,每次通过我的循环 我可以看到我的内存使用量增加而且从不减少。我目前正在使用Storyboards和ARC。

我怎样才能正确释放UILabel,因为ARC似乎没有为我做这件事?

@implementation myViewController
CGPoint tmpPoint;
NSMutableArray *allDots;
/// more code here
//
// This method is called repeatedly from another loop
-(void)createLabels{
//remove any previous labels
//I'm pretty sure this is not actually clearing the UILabels but rather the pointer to the labels?
    for(short i=0; i<10; i++){
        UILabel *junkDot=[allDots objectAtIndex:i];
        junkDot=nil;
    }
// Either of these statements should clear the references/pointers
//        [allDots removeAllObjects];
    allDots=[[NSMutableArray alloc] init];

//create a new group of labels
    for(short i=0; i<10; i++){
        // code to generate Point values
        [self makeLabel:tmpPoint];
    }
}

-(UILabel*)makeLabel:(CGPoint)thePoint{
    CGRect xFrame=CGRectMake(thePoint.x, thePoint.y, 40, 20);
    UILabel *tmpLabel=[[UILabel alloc] initWithFrame:xFrame];

    [self.view addSubview:tmpLabel];

    [allDots addObject:tmpLabel];

    return tmpLabel;
}

3 个答案:

答案 0 :(得分:4)

您需要了解内存管理的基础知识。

在ARC中,只要存在至少一个强引用,对象就会保留在内存中。只要不再对某个对象有任何强引用,它就会被释放。

NSArray(或NSMutableArray)对添加到其中的任何对象保持强引用。如果从可变数组中删除对象(使用,例如removeObjectAtIndex:),则数组会释放它的强引用。

从数组中获取对象然后将局部变量设置为nil的代码绝对不会浪费时间:

for(short i=0; i<10; i++){
    UILabel *junkDot=[allDots objectAtIndex:i];
    junkDot=nil;
}

使用addSubview:向视图层次结构添加视图对象时,superview还会保留对该对象的强引用。

因此,如果您创建了一堆标签并将它们放在一个数组中并将它们添加为内容视图的子视图,则每个标签都有2个强引用。标签不会被取消分配,直到它从它的超级视图中移除并从阵列中删除。

答案 1 :(得分:2)

@implementation myViewController
CGPoint tmpPoint;
NSMutableArray *allDots;

将上面的代码替换为代码

@implementation myViewController {
CGPoint tmpPoint;
NSMutableArray *allDots;
}

答案 2 :(得分:0)

除非你在视图中保留UILabel对象,否则它们应该从数组中删除,至少只需要removeAllObjects方法。如果不是,那么其他东西就会保留它们。

在您的代码中,您从allDots数组中提取项目,但之后您仍然在其他地方使用UILabel。该数组已经释放了该对象,但由于它仍然在某处使用。由于数组只保存引用,因此您只需将保留计数减少1.对象不会占用更多或更少的内存,只需少一点保留。

您可以轻松地设置一些NSLog或记录断点,以查看发生的事情:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSMutableArray *allDots = [@[] mutableCopy];

    for(NSInteger i=0; i<10; i++){
        UILabel *i = [UILabel new];
        [allDots addObject: i];
    }
    NSLog(@"Contents of array %@", [allDots description]);
    // Either of these statements should clear the references/pointers

    [allDots removeAllObjects];
    NSLog(@"Contents of array %@", [allDots description]);
    // Do any additional setup after loading the view, typically from a nib.
}

2014-06-29 11:25:59.185 Loper[47174:2208182] Contents of array (
"<UILabel: 0x10b76c370; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b768ef0>>",
"<UILabel: 0x10b82b870; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b82b9d0>>",
"<UILabel: 0x10b834c10; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b82d510>>",
"<UILabel: 0x10b82a9b0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b8408b0>>",
"<UILabel: 0x10b82ab10; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b834dd0>>",
"<UILabel: 0x10b8326e0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b837a80>>",
"<UILabel: 0x10b832840; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b80ebb0>>",
"<UILabel: 0x10b8329a0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b841a90>>",
"<UILabel: 0x10b846290; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b80eeb0>>",
"<UILabel: 0x10b8465a0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <_UILabelLayer: 0x10b846700>>"
)

2014-06-29 11:25:59.185 Loper[47174:2208182] Contents of array (
)

要逐步了解正在发生的事情,只需在那里抛出一个常规断点,然后逐步查看代码,看看谁在坚持参考。

其他选项是运行静态分析器并查看是否检测到任何保留循环,或者使用泄漏或分配工具打开仪器中的项目,并查看设备底层发生的情况。