ARC:负责Allocations配置文件中堆增长的局部变量

时间:2013-11-15 09:38:56

标签: objective-c memory-management automatic-ref-counting

我以编程方式设置了一个带有2个按钮的UINavigationBar。

-(void)setUpNavigationBar{
  //The Navbar
  UIImage *backgroundImage = [UIImage imageNamed:@"top_bar_gradient"];
  UINavigationBar *naviBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, MAINBAR_WIDTH, MAINBAR_HEIGHT)];
  [naviBar setTintColor:[UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0]];
  [naviBar setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];

  //Right Button
  UIButton *rButton = [UIButton buttonWithType:UIButtonTypeCustom];
  UIImage *rButImage = [UIImage imageNamed:@"top_icon_menu2"];
  [rButton setBackgroundImage:rButImage forState:UIControlStateNormal];
  [rButton addTarget: self.viewDeckController action:@selector(toggleRightView) forControlEvents:UIControlEventTouchUpInside];
  [rButton setFrame:CGRectMake(MAINBAR_BUTTON_X, MAINBAR_BUTTON_Y, MAINBAR_BUTTON_WIDTH, MAINBAR_BUTTON_HEIGHT)];
  UIBarButtonItem *rightButton = [[UIBarButtonItem alloc]initWithCustomView:rButton];

  //Left Button
  UIButton *lButton = [UIButton buttonWithType:UIButtonTypeCustom];
  UIImage *lButImage = [UIImage imageNamed:@"top_icon_menu1"];
  [lButton setBackgroundImage:lButImage forState:UIControlStateNormal];
  [lButton addTarget: self.viewDeckController action:@selector(toggleLeftView) forControlEvents:UIControlEventTouchUpInside];
  [lButton setFrame:CGRectMake(MAINBAR_BUTTON_X, MAINBAR_BUTTON_Y, MAINBAR_BUTTON_WIDTH, MAINBAR_BUTTON_HEIGHT)];
  UIBarButtonItem *leftButton = [[UIBarButtonItem alloc]initWithCustomView:lButton];

  //Put it all together
  naviBarItem.leftBarButtonItem = leftButton;
  naviBarItem.rightBarButtonItem = rightButton;
  naviBar.items = [NSArray arrayWithObjects:naviBarItem,nil];

  self.navigationItem.leftBarButtonItem = leftButton;

  [self.view addSubview:naviBar];

  // This was my approach preventing the heap growth.
  rightButton = nil;
  leftButton = nil;
}

- (void)viewDidLoad
{
  [super viewDidLoad];
  [self setUpNavigationBar];
}

我通过乐器分析应用程序并在XCode 5中获取Heapshots(他们称为“Generations”)。我想首先解决我自己的对象的问题,并希望其他堆增长问题只是从我自己的对象“级联”。

所以我看到每次关闭并打开应用程序时,UIBarButtonItem会将堆增加448个字节(这是我拍摄快照后的例程)。由于有4个物体存在,似乎物体没有被释放,我使用ARC

问题是每次关闭并打开应用程序时,我的堆增长了大约200 kb。这是内存泄漏:

Instruments Allocations

深入挖掘我发现它是我setUpNavigationBar函数中的UIBarButtonItem。

enter image description here

所以我的问题是如何防止内存泄漏?由于ARC已启用,我无法自行释放该对象。

1 个答案:

答案 0 :(得分:2)

您犯的错误是每次输入setUpNavigationBar时都在创建新的导航栏。您创建导航栏,然后将其添加为子视图,这意味着它将被保留,并且您将丢失对导航栏的引用,因此您永远不能删除和释放它。

我不知道为什么这个方法被多次调用,因为你只能从viewDidLoad调用它,但是你可能会奇怪地处理低内存。

您应该将导航栏存储为属性。在你的班级界面中使用:

@property (nonatomic, strong) UINavigationBar *naviBar;

然后将您的代码更改为:

-(void)setUpNavigationBar{
    if (!self.naviBar)
    {
        //The Navbar
        UIImage *backgroundImage = [UIImage imageNamed:@"top_bar_gradient"];
        UINavigationBar *naviBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, MAINBAR_WIDTH, MAINBAR_HEIGHT)];
        self.naviBar = naviBar;
        [naviBar setTintColor:[UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:1.0]];
        [naviBar setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];

        //Right Button
        UIButton *rButton = [UIButton buttonWithType:UIButtonTypeCustom];
        UIImage *rButImage = [UIImage imageNamed:@"top_icon_menu2"];
        [rButton setBackgroundImage:rButImage forState:UIControlStateNormal];
        [rButton addTarget: self.viewDeckController action:@selector(toggleRightView) forControlEvents:UIControlEventTouchUpInside];
        [rButton setFrame:CGRectMake(MAINBAR_BUTTON_X, MAINBAR_BUTTON_Y, MAINBAR_BUTTON_WIDTH, MAINBAR_BUTTON_HEIGHT)];
        UIBarButtonItem *rightButton = [[UIBarButtonItem alloc]initWithCustomView:rButton];

        //Left Button
        UIButton *lButton = [UIButton buttonWithType:UIButtonTypeCustom];
        UIImage *lButImage = [UIImage imageNamed:@"top_icon_menu1"];
        [lButton setBackgroundImage:lButImage forState:UIControlStateNormal];
        [lButton addTarget: self.viewDeckController action:@selector(toggleLeftView) forControlEvents:UIControlEventTouchUpInside];
        [lButton setFrame:CGRectMake(MAINBAR_BUTTON_X, MAINBAR_BUTTON_Y, MAINBAR_BUTTON_WIDTH, MAINBAR_BUTTON_HEIGHT)];
        UIBarButtonItem *leftButton = [[UIBarButtonItem alloc]initWithCustomView:lButton];

        //Put it all together
        naviBarItem.leftBarButtonItem = leftButton;
        naviBarItem.rightBarButtonItem = rightButton;
        naviBar.items = [NSArray arrayWithObjects:naviBarItem,nil];

        self.navigationItem.leftBarButtonItem = leftButton;

        [self.view addSubview:naviBar];
    }
}