从另一个 viewController 的视图添加 UIImageView 到另一个 viewController 的视图时的内存管理
所以看起来我在整个项目中没有检测到泄漏,而且我有很多部分可以做各种事情。
然而,我发现我遇到了一些分配问题,通过泄漏工具中的标记堆向我证明了这一点,这些问题在使用带有外部屏幕的 iPad 时大多数时候都会发生。该应用程序被编程为在连接到外部屏幕时表现不同。
我有一个可缩放的 UIScrollView 地图部分,我可以进出。当单独使用 iPad 并检查标记堆时,堆增长最终将降至 0 字节,这很好。然而,插入外部屏幕后,图像会发送到外部屏幕,外部屏幕使用另一个视图控制器,退出地图时检查标记堆大约每次都在 6-7 MB 左右,而其他堆没有太大减少生长。坏的。
我发现,我完全没有正确处理外部 UIImageView 的释放,当我浏览它时,这一点对我来说是显而易见的。我稍后会对此进行更多解释。
在我继续解释之前,重要的是,我很抱歉花了这么长时间,但我发誓我听说有一个例外,如果将分配的对象从另一个视图添加到另一个视图,则不会将其放入 dealloc 中,因为我不这样做不拥有它,因此不负责释放。无论我是否释放它,我都会得到相同的行为。但实际上我认为它永远不会按照我的代码当前设置的方式解除分配。所以我认为我的问题是我没有从内存中释放图像视图......但问题仍然存在,在这种情况下我该在哪里执行此操作!
在视图 A 的 initWithFrame 方法中,我将视图添加到外部屏幕(如果已连接):
if(exScreenEnabled==1){
mapImageViewEx = [[UIImageView alloc] init];
CGPoint p = mapScrollView.contentOffset;
mapImageViewEx.frame = CGRectMake((p.x*-1), (p.y*-1), mapImageView.frame.size.width, mapImageView.frame.size.height);
NSString *mapExFileLocation = [[NSBundle mainBundle] pathForResource:[map_List objectAtIndex:mapNum] ofType:@"png"];
NSData *mapExIMGData = [NSData dataWithContentsOfFile:mapExFileLocation];
mapImageViewEx.image = [UIImage imageWithData:mapExIMGData];
UIView *containerExViewP = (UIView*)[del.switchExVC.view viewWithTag:9000];
[containerExViewP addSubview:mapImageViewEx];
}
在外部 viewController 的 viewDidLoad 方法中,当应用程序启动且用户选择屏幕分辨率时,已添加了一个 containerView。其工作原理与 iPad 窗口的视图控制器几乎相同,用于交换视图:
CGRect frame = CGRectMake(0, 0, 1024, 768);
containerExView = [[UIView alloc] initWithFrame:frame];
[containerExView setTag:9000];
self.view = containerExView;
让我们将此外部视图控制器称为“视图 B”
因此,这看起来像是问题开始的地方:当用户在屏幕上按下后退按钮时如图所示,如果连接了外部屏幕,View A 会执行 View B 监听的 NSNotificationCenter,以删除 View B 容器中的子视图。这是视图 B 中的方法:
- (void)removeExView{
[[self.view.subviews objectAtIndex:0] removeFromSuperview];
NSLog(@"REMOVED EX VIEW");
UIImage *idleExImage = [UIImage imageNamed:@"idle4.png"];
UIImageView *idleExImageView = [[UIImageView alloc] initWithImage:(UIImage *)idleExImage];
CGRect idleExFrame = CGRectMake(0, 0, 1024, 768);
idleExImageView.frame = idleExFrame;
[self.view addSubview:idleExImageView];
[idleExImageView release];
}
从索引 0 处的视图 B 容器中删除子视图,然后显示默认图像。
所以,我最好的猜测是,即使子视图(即图像视图)被删除,它也不一定从内存中释放。但你如何访问它呢?这还是问题吗?也许它确实必须被释放,但永远不会达到这一点,因为视图首先被意外删除。我只是不知道,因为我还不熟悉这种情况应该如何正确处理。预先感谢您可以提供的任何帮助。
So it looks like I have no leaks detected throughout my entire project, and I have lots of sections that do various things.
However, I found that I am having some allocation issues, proven to me with mark heap in leaks instrument, which have happened most of the time when using the iPad with an external screen. The app is programmed to behave differently when connected to an external screen.
I have a zoomable UIScrollView map section that I can go in and out of. When using the iPad by itself, and checking the mark heap, the heap growth will eventually go down to 0 bytes, which is good. However, with the external screen plugged in, an image is sent to the external screen, which uses another view controller, and checking the mark heap when exiting the map is around 6-7 MB just about every time without much decrease in the other heap growths. BAD.
The thing I found was, that I'm totally not handling the release of the external UIImageView correctly at all, and this was obvious to me when I just glanced over it. I'll explain more about that in a bit.
Important thing before I continue explaining, and I apologize for making this so long, but I swear I've heard there's an exception for not putting an alloc'd object in dealloc if it is added to another view from another view, because I don't own it, thus not responsible for dealloc'ing. Whether I dealloc it or not, I get the same behavior. But I actually don't think it would ever get to dealloc the way my code is setup currently. So I think my problem is that I'm not releasing the image view from memory... but the question remains, where do I do that in this case!
In View A's initWithFrame method, I have the view added to the external screen if it's connected:
if(exScreenEnabled==1){
mapImageViewEx = [[UIImageView alloc] init];
CGPoint p = mapScrollView.contentOffset;
mapImageViewEx.frame = CGRectMake((p.x*-1), (p.y*-1), mapImageView.frame.size.width, mapImageView.frame.size.height);
NSString *mapExFileLocation = [[NSBundle mainBundle] pathForResource:[map_List objectAtIndex:mapNum] ofType:@"png"];
NSData *mapExIMGData = [NSData dataWithContentsOfFile:mapExFileLocation];
mapImageViewEx.image = [UIImage imageWithData:mapExIMGData];
UIView *containerExViewP = (UIView*)[del.switchExVC.view viewWithTag:9000];
[containerExViewP addSubview:mapImageViewEx];
}
In the external viewController's viewDidLoad method, a containerView had been added when the application started and the user chose the screen resolution. Working almost the same as the iPad window's view controller, it's for swapping in and out views:
CGRect frame = CGRectMake(0, 0, 1024, 768);
containerExView = [[UIView alloc] initWithFrame:frame];
[containerExView setTag:9000];
self.view = containerExView;
Let's just call this external viewController's "View B"
So this looks like where the problem starts: When the user pushes the back button when they are in the map, if an external screen is connected, View A performs an NSNotificationCenter that View B listens to, to remove subviews in View B's container. Here's the method in View B:
- (void)removeExView{
[[self.view.subviews objectAtIndex:0] removeFromSuperview];
NSLog(@"REMOVED EX VIEW");
UIImage *idleExImage = [UIImage imageNamed:@"idle4.png"];
UIImageView *idleExImageView = [[UIImageView alloc] initWithImage:(UIImage *)idleExImage];
CGRect idleExFrame = CGRectMake(0, 0, 1024, 768);
idleExImageView.frame = idleExFrame;
[self.view addSubview:idleExImageView];
[idleExImageView release];
}
The subview's are removed from View B's container at index 0, and then default image is displayed.
So, my best guess is, even though the subview was removed, which is the image view, it's not necessarily released from memory. But how would you access this? Is this even the problem? Perhaps it does have to be dealloc'd but can never get to this point because the view is unexpectedly removed first. I just don't know, because I'm not familiar yet how this situation should be handled properly. Thanks in advance for any help you can provide.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
有点难以猜测这一点,但我想说的是这些行,
这些行可以而且应该在添加到视图层次结构后发布,
除非您故意保留对这些行的引用以获取上面片段中未显示的内容。
Kind of tough to guess at this, but I'd say it's these lines
These can and should be release after they've been added to the view hierarchy
unless you are keeping a reference to these intentionally for something not shown in the snippets above.
[containerExViewP addSubview:mapImageViewEx];
在此行之后使用 [containerExViewP release];
[containerExViewP addSubview:mapImageViewEx];
after this line use [containerExViewP release];