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



Xcode 5, iOS7

我有一个应用程序,在循环中创建uilabel,在数组中引用它们。在反复调用"create"方法后,我注意到我的内存使用量增加了。我想清除数组和相关的UILabel对象来释放内存,因为它似乎没有发生与我目前的代码。相反,每次都通过我的循环我可以看到我的内存使用量在增加,从未减少。我目前正在使用故事板和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;
}

您需要阅读内存管理的基础知识。

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

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

从数组中获取对象,然后将局部变量设置为nil的代码除了浪费时间之外什么都没有做:

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

当你使用addSubview:将一个视图对象添加到视图层次结构中时,父视图也会保持对该对象的强引用。

因此,如果你创建了一堆标签,并将它们放在一个数组中,并将它们添加为内容视图的子视图,那么每个标签都有2个强引用。标签不会被释放,直到它从父视图和数组中被移除。

@implementation myViewController
CGPoint tmpPoint;
NSMutableArray *allDots;

将以上代码替换为代码

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

除非您在视图中保留UILabel对象在屏幕上,否则它们应该至少通过removeallojects方法从数组中删除。如果不是,那就是有别的东西在留住他们。

在您的代码中,您正在从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 (
)

要一步一步地找出发生了什么,只需在那里抛出一个常规的断点,然后逐步检查代码,看看是谁持有引用。

其他选项是只是运行静态分析器,看看是否检测到任何保留循环,或在仪器中打开您的项目,使用泄漏或分配工具,看看设备上发生了什么。

最新更新