【问题标题】:ARC & Memory managment in my app我的应用程序中的 ARC 和内存管理
【发布时间】:2013-06-18 11:26:54
【问题描述】:

编辑

我发现我的屏幕不会为零,因为它们保留了 RefCt,但我的问题是为什么 RefCt 不是 0?我只是创建、添加和删除视图。还添加了仪器的屏幕转储:

所以你在开头看到

Malloc 1 initwithframe,保留:2 initwithframe,发布:1 -[UIView(内部)_addSubview:positioned:relativeTo:],保留:2 Quartzcore CALAyer layoutSublayers,retain: 3 Quartzcore CALAyer layoutSublayers,发布:2 然后在我的代码中删除这个视图 removeFromSuperView: 1

谁能解释一下:

 -[UIView(Internal) _addSubview:positioned:relativeTo:], retain : 2

行?我想这就是为什么我的观点仍然有一个 RefCt。

结束

我正在尝试清理我的代码并最终加快我的应用程序的速度,但我认为我并没有真正了解整个内存管理。基本上,我的应用程序有一个对用户可见的视图,但它可以根据用户在菜单中选择的内容切换到不同的视图。现在我认为最符合逻辑的是一次只分配一个视图并占用内存空间,当用户选择另一个视图时,应该释放当前视图并分配所选视图。在选择新视图时,我尝试通过执行以下操作来创建它:

- (void)removeMenus {
    @autoreleasepool {
        for (UIView *view in container.subviews) {
            NSLog(@"View to be removed: %@", view);
            [view removeFromSuperview];
        }
    }
}

假设用户选择再次显示开始屏幕。这段代码将运行:

- (void)createStartScreen {
    if (startScreen == nil) {
        startScreen = [[StartScreen alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height)];
        startScreen.delegate = self;
        startScreen.layer.shadowColor = [[UIColor blackColor] CGColor];
        startScreen.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
        startScreen.layer.shadowRadius = 5.0f;
        startScreen.layer.shadowOpacity = 1.0f;
    }
}

我在那里放了一个断点,发现 startscreen 不是 nil,而我认为应该是因为我从 superview 中删除了它(也尝试清除该 var 的指针)。如果我理解正确,startscreen 的保留计数不为零,对吗?另外我正在使用 ARC,所以我认为 ARC 可以很好地处理这个问题。

释放用户不再可见的视图以保留内存的正确方法是什么?

【问题讨论】:

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


    【解决方案1】:

    这取决于 ivar startScreen 是什么。如果startScreen 在您的视图控制器中被定义为一个强ivar,那么它在分配后的引用计数为1,在您将其设置为视图层次结构中的子视图后引用计数为2。然后,从其父视图中删除视图只会将引用计数减少到 1,并且您必须显式地将变量 nil 才能释放它。

    另一种选择是您的视图在 Storyboard 或 XIB 文件中定义,并通过插座连接到您的视图控制器。在这种情况下,您的视图 ivar 必须设置为弱变量,因为它已经被其他人强占。

    了解强限定符和弱限定符 here 之间的区别。

    最后一件事 - 为了更好的可读性,通常的惯例是为要延迟实例化的变量定义一个属性,然后将您编写的代码放在覆盖的 getter 方法中的 createStartScreen 中。

    【讨论】:

    • 我真的不明白你回答的最后一句话。你能举一个延迟加载的例子吗?
    • 当然。在您的情况下,我不会在使用视图之前调用createStartScreen,而是定义一个@property (strong, nonatomic) StartScreen *startScreen; 并定义一个getter,如下所示:- (StartScreen *)startScreen { if (!_startScreen) { _startScreen = [[StartScreen alloc] init...]; // Do stuff } return _startScreen; }。然后,您所要做的就是访问self.startScreen,您的视图将被实例化,但仅在第一次访问时。当然,你可以在需要的时候设置self.startScreen = nil,在需要的时候将refcount减一。
    【解决方案2】:

    如果您想更清楚地了解阻止您的视图发布的原因,您应该使用 Instruments 的分配模板来分析您的应用。这将告诉您每个保留和释放的调用站点,包括由 ARC 和系统框架执行的那些。如果您的视图是从 XIB 文件实例化的,那么在一定程度上,系统框架会控制它们的生命周期。

    我可以提供的下一条明智的建议是,现在停止考虑绝对保留计数。假装-retainCount 方法不存在。真的。我不是在开玩笑。其他比我更有权威的人已经解释了为什么保留计数没用的细节,所以如果你不相信我的话,请阅读this

    话虽如此,我没有足够的信息来确定,但通常过多的内存使用不是由于一两个视图尚未发布。仪器可以让您了解真正的问题所在。

    【讨论】:

    • 感谢您的评论。我来看看 Xcode 的 Instruments
    猜你喜欢
    • 2012-07-28
    • 2013-01-17
    • 1970-01-01
    • 2011-11-14
    • 1970-01-01
    • 1970-01-01
    • 2012-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多