在循环中分配是否正确,以便创建多个对象?
for (int i = 0; i < limit; i++)
{
UILabel *lbl = [[UILabel alloc] initWithFrame:(CGRectMake(i*20, 0, 20, 20))];
lbl.textColor = [UIColor whiteColor];
lbl.font = [UIFont systemFontOfSize:16];
lbl.backgroundColor = [UIColor blackColor];
lbl.text = [NSString stringWithFormat: @"%d", i];
[self.view addSubview:lbl];
[lbl release];
}
在我的项目中,我在几个 uiscrollview 面板中创建了数百个小标签。 即使我在这些标签上调用 release 方法,我在打手势时也会表现不佳:即使在栅格化视图之后也是如此。感觉像所有这些标签仍然存在,等待从记忆中冲洗 所以我对这个问题的暗示与我分配的方式有关。
我缺少什么?...
答案 0 :(得分:3)
不会释放内存,因为您将UILabel
添加到视图中。即使您调用release,因为视图仍然保留它们。
答案 1 :(得分:2)
在self.view
发布之前,所有这些标签确实会继续存在。您的代码为对象分配内存并初始化对象,然后将对象的所有权传递给您的视图。你的release
意味着当视图被释放时你将不会保留它们的所有权,因此系统可以自由地摆脱它们:你的release
本身并没有摆脱对象。 (我在下面添加了一个插图,以防它不清楚。)
这不仅仅是一个内存问题,因为UILabel对象具有各种其他开销:它自己的十几个属性和方法,它从UIView继承的几十个属性和方法,另外十二个继承自UIResponder,以及来自UIObject的另外十几个。因此,UILabel可以做各种漂亮的事情:拥有颜色和阴影以及alpha透明度并管理自动换行并附加手势识别器并设置动画并拥有自己的子视图等。
对于更轻松的解决方案,您可以使用NSString的drawInRect:withFont:
方法(从UIKit Additions获取)来绘制相同的文本。这些UILabel开销都没有,尽管它没有任何细节。尽管如此,只需付出一点努力就可以完全按照自己的意愿行事。
这可能有点矫枉过正,但有一个例子:
您的ViewController分配并初始化查看。内存中有一个View副本,ViewController保留View的所有权,直到您(很可能)以dealloc
方法释放ViewController(除非您在此之前手动释放它)。
您的ViewController分配并初始化标签。内存中有一个Label副本,ViewController保留Label的所有权。
通过调用View的addView
方法,您将标签的所有权添加到视图中(除了指示它显示标签之外)。内存中仍然有一个Label副本,现在有两个对象拥有它。
通过调用Label的release
方法,ViewController 放弃了Label的所有权。内存中仍然有一个Label副本,View仍然拥有它。
每次循环都会重复步骤2 - 4,每次View都保留所分配标签的所有权。
每次应用程序到达其运行循环结束时(在应用程序运行时反复发生)如果有任何已分配的对象 没有所有者 然后释放用于存储它们的内存。因为您的View仍然拥有所有这些标签,所以继续使用为其分配的内存。
答案 2 :(得分:1)
在您的界面中,在任何给定时间屏幕上的用户可以看到多少个标签?由于您将标签放在UIScrollViews中,我假设用户看到的数量远远少于您分配和绘制的数百个。如果用户不能同时看到数百个标签,为什么要一次创建它们呢?
您应该考虑采用类似于UITableViewDataSource协议的模式。 UITableView不会预先分配500个UITableViewCell。它仅在需要绘制时才向其dataSource询问单元格。此外,它将回收屏幕外的单元格,以抵消从头开始分配/初始化UITableViewCell的成本。正确配置后,内存中只会有用户可以在屏幕上看到的UITableViewCell数量。
因此,考虑将UIScrollView设计为仅在需要绘制时请求标签,然后在屏幕外移动时将未使用的标签保留在内存中。这样,您在内存中只有用户可以在屏幕上看到的标签数量。
有一些示例代码通过子类化UIScrollView来显示如何执行此操作:
查看“平铺”项目。它通过引入比例分辨率使这一概念更进一步,但它应该足以指出你正确的方向。
答案 3 :(得分:0)
如果你要创造数百个,它将非常昂贵,并且将成为表现不佳的途径。
你可能会做得更好的是使用可变数组/集创建重用池。
当您在屏幕上需要一个时,查看该组中是否有一个,如果没有,则创建一个。然后当它从屏幕滚动时,将其从superview中删除,并将其添加到重用池中。喜欢tableViewCells。通过这种方式,您只需要创建多个可以同时在屏幕上显示的内容。
希望这会有所帮助...