【问题标题】:Table view images never being released表格视图图像永远不会被发布
【发布时间】:2015-01-11 07:51:06
【问题描述】:

我正在对我的一个应用程序进行重大更新,并试图减少内存使用量并使其更清洁、更快。我正在使用 Instruments 来分析应用程序并且我正在查看 UIImage 分配,当应用程序启动时我有大约 10 个(虽然一个是状态栏图标?不知道为什么包括在内)。当我打开我的设置视图控制器(在 iPad 上的拆分视图控制器中)时,它基本上有一个包含每个表格视图单元格的图像,这很多。首次展示它会添加 42 张图像。当我关闭这个视图控制器时,仍然有 52 个图像,而现在应该只有 10 个。如果我再次展示控制器,现在有 91 个图像。这一直在上升。 Instruments 没有说有泄漏,我不知道发生了什么。每个单元格设置一个图像,如

cell.imageView.image = [UIImage imageNamed:@"Help-Icon"];

我怎样才能弄清楚为什么这些图片没有被发布?

编辑: 我认为它现在正在释放图像。我从直接设置imageView图片改为setImage:,所以现在表格单元格是这样的:

    cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
    }
    cell.textLabel.text = NSLocalizedString(@"Homepage", @"Homepage");
                UIImage *cellImage = [UIImage imageNamed:@"Homepage-Icon"];
                [cell.imageView setImage:cellImage];
[MLThemeManager customizeTableViewCell:cell];
return cell;

MLThemeManager 是一个单例,它使用主题类将单元格的属性设置为主题,如文本标签颜色、突出显示颜色、详细文本标签颜色和背景颜色。

【问题讨论】:

  • 阅读 imageNamed: 的文档。图片已缓存。
  • 但不应该在初始演示后不添加图像吗?它说更多的被添加到内存中并且永远不会被释放。
  • 你能分享你的 CellForRowAtIndexPath 吗?
  • 是的,我会进行编辑并添加代码

标签: ios objective-c memory-management memory-leaks


【解决方案1】:

这里可能的原因是因为您的设置视图控制器没有被释放(没有从内存中释放)。当视图控制器从内存中释放时,无论视图控制器中有多少图像,它都会从内存中释放(删除)所有图像对象。

如何检查你的视图控制器是否被释放(释放)?

步骤:

  1. 在 Xcode 中长按运行按钮。您会看到一个小弹出窗口,从中选择 Profile。您可以看到新图标替换了 Run 图标。 (同样,您可以将其更改为运行按钮以运行应用程序)。

  1. 单击此按钮将开始分析您的应用程序。

  2. 工具窗口中选择Allocations部分。分配列表视图上方有一个文本字段。单击该字段并写下您的视图控制器名称。 (在您的情况下是 SettingViewController)。

  1. 您只能看到与您刚刚输入的关键字相关的过滤结果。现在去模拟器 - >模拟你的流程。从您的视图控制器弹出并检查 Instruments 离开该视图控制器后是否仍在列表中。如果它在列表中,则视图控制器不会从内存中释放,并且每次打开该视图控制器时都会增加内存,并且在应用程序运行之前永远不会释放。

我们如何解除分配视图控制器?

我将尝试解释一些我知道的解除分配控制器的方法。

[ 1 ] 覆盖视图控制器中的 dealloc 方法并在其中释放对象。主要是可变变量和委托。在-dealloc 方法上放置一个调试断点,并确保在您离开该控制器时调用它。

注意:如果您为 UIPickerViewUIPopoverControllerUIImagePickerController 等类创建全局变量并为此设置委托,则这些委托必须是 nil in @987654328 @ 方法。

例如

目标 C 代码:

//---------------------------------------------------------------

#pragma mark
#pragma mark Memory management methods

//---------------------------------------------------------------

- (void) dealloc {
    [self.tableView setDelegate:nil];
    [self.tableView setDataSource:nil];
}

Swift 代码:

deinit {
    self.tableView.dataSource = nil
    self.tableView.delegate = nil
}

[ 2 ] 子类的全局对象也需要重写-dealloc方法并释放相关对象和委托。必须调用类似的 dealloc 方法。

例如

检查这个场景:假设您创建了一个名为MenuViewUIView(或任何其他视图)的子类。而且你已经在你的视图控制器中创建了这个类的一个全局变量,它的 dealloc 方法将在视图控制器的 dealloc 方法之前被调用。

@property (nonatomic, strong) MenuView    *menuView;

所以这里MenuView 类需要重写-dealloc 方法,并且必须在调用视图控制器的dealloc 方法之前调用。

这样在离开整个容器之前,它的子视图会被释放并从内存中删除。

Instruments 中检查 MenuView 类,该对象是否仍然是他们的?

如果它的 dealloc 方法未被调用,则 MenuView 类的对象仍在内存中,并且您的视图控制器类正在引用该对象。因此,即使您的视图控制器的 -dealloc 被调用,它也不会被释放,因为 MenuView 类对象是活动的。


[ 3 ] 您需要将weak 引用设置为IBOutlet。例如

目标 C 代码:

@property (nonatomic, weak) IBOutlet UITableView   *tableView;

Swift 代码:

@IBOutlet weak var tableView: UITableView!

如果有什么不清楚的地方欢迎追问。

【讨论】:

  • 致所有观众 - 提出您的意见并随时进行编辑。
  • 视图控制器被释放,图像现在被移除。我在某处读到使用情节提要不会解除分配,在我阅读此内容之前,我删除了情节提要并将其全部转换为代码,因此它之前可能还没有解除分配。谢谢你的回答,很详细!
  • @Wongzigii ARC 维护发布和保留计数,这在早期是没有的。但是我在回答中解释的那些代表和全局变量需要nil
【解决方案2】:

不要使用图像资产...将图像复制到您的项目中的文件夹中,然后通过带有 imageWithContentOfFile 的代码加载它对我有用

【讨论】:

    【解决方案3】:

    尝试使用imageWithContentsOfFile加载图片。

    正如 rmaddy 所说,imageNamed 会让你的图像留在缓存中,这就是你的内存问题的原因

    【讨论】:

    • 嗯,我使用资产目录,我不认为它可以使用imageWithContentsOfFile,但我会尝试。
    • 你试过了吗?有帮助吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-28
    • 1970-01-01
    • 2011-11-06
    • 2016-06-12
    • 1970-01-01
    相关资源
    最近更新 更多