更新
澄清问题的背景;问题不在于如何避免这个问题,而在于澄清文档的含义,因为我的实验表明我希望根据文档卸载的视图不会卸载。我想了解这是一个错误,还是我误解了文档。为了解决这个问题,我知道在viewWillAppear中设置图像而不是viewDidLoad,并在viewDidDisappear中将图像设置为nil,正在释放内存,应用程序不会崩溃。但是,我想了解内存是否应该与初始代码一起发布,因为实验是模拟将这样的视图控制器作为出口,并在Interface Builder中设置UI图像(背景...),而不是设置它们在viewWillAppear的代码中......
的原件:
我试图了解iOS6的一些新方面,如View Controller Programming Guide中所述:
在iOS 6及更高版本中,视图控制器在需要时卸载自己的视图 视图控制器的默认行为是在首次访问视图属性时加载其视图层次结构,然后将其保留在内存中,直到视图控制器被丢弃为止。视图用于在屏幕上绘制自身的内存可能非常大。但是,当视图未附加到窗口时,系统会自动释放这些昂贵的资源。大多数视图使用的剩余内存足够小,系统自动清除和重新创建视图层次结构是不值得的。
假设我正在使用rootViewController创建一个简单的应用程序。
这个rootViewController有一些子视图控制器,都声明为IBOutlets,而不是在代码中分配。
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController1;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController2;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController3;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController4;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController6;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController7;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController8;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController9;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController10;
rootViewController有几个按钮,按下每个按钮,对每个childViewController执行简单的presentModalViewController操作。
-(IBAction)showChild1Action:(id)sender{
[self presentModalViewController:self.childViewController1 animated:true];
}
每个childViewController都有一个关闭按钮,用于关闭子视图控制器。
-(IBAction)closeAction:(id)sender{
[self dismissModalViewControllerAnimated:true];
}
我对文档的期望是子视图控制器视图对象将从内存中释放,因为子视图控制器被解除。
然而,我故意测试大型视图对象,并在这样的应用程序上运行配置文件,内存使用量随着每个子控制器的呈现而不断增长,并且在我呈现子控制器#7之后应用程序最终崩溃。
您对iOS6在这方面的变化有何了解?
RootViewController.h
#import <UIKit/UIKit.h>
#import "ChildViewController.h"
@interface RootViewController : UIViewController
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController1;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController2;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController3;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController4;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController5;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController6;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController7;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController8;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController9;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController10;
-(IBAction)showChild1Action:(id)sender;
-(IBAction)showChild2Action:(id)sender;
-(IBAction)showChild3Action:(id)sender;
-(IBAction)showChild4Action:(id)sender;
-(IBAction)showChild5Action:(id)sender;
-(IBAction)showChild6Action:(id)sender;
-(IBAction)showChild7Action:(id)sender;
-(IBAction)showChild8Action:(id)sender;
-(IBAction)showChild9Action:(id)sender;
-(IBAction)showChild10Action:(id)sender;
@end
RootViewController.m
#import "RootViewController.h"
@interface RootViewController ()
@end
@implementation RootViewController
@synthesize level2ViewController1;
@synthesize level2ViewController2;
@synthesize level2ViewController3;
@synthesize level2ViewController4;
@synthesize level2ViewController5;
@synthesize level2ViewController6;
@synthesize level2ViewController7;
@synthesize level2ViewController8;
@synthesize level2ViewController9;
@synthesize level2ViewController10;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
-(IBAction)showChild1Action:(id)sender{
self.level2ViewController1.index=0;
[self presentModalViewController:self.level2ViewController1 animated:true];
}
-(IBAction)showChild2Action:(id)sender{
self.level2ViewController2.index=1;
[self presentModalViewController:self.level2ViewController2 animated:true];
}
-(IBAction)showChild3Action:(id)sender{
self.level2ViewController3.index=2;
[self presentModalViewController:self.level2ViewController3 animated:true];
}
-(IBAction)showChild4Action:(id)sender{
self.level2ViewController4.index=3;
[self presentModalViewController:self.level2ViewController4 animated:true];
}
-(IBAction)showChild5Action:(id)sender{
self.level2ViewController5.index=4;
[self presentModalViewController:self.level2ViewController5 animated:true];
}
-(IBAction)showChild6Action:(id)sender{
self.level2ViewController6.index=5;
[self presentModalViewController:self.level2ViewController6 animated:true];
}
-(IBAction)showChild7Action:(id)sender{
self.level2ViewController7.index=6;
[self presentModalViewController:self.level2ViewController7 animated:true];
}
-(IBAction)showChild8Action:(id)sender{
self.level2ViewController8.index=7;
[self presentModalViewController:self.level2ViewController8 animated:true];
}
-(IBAction)showChild9Action:(id)sender{
self.level2ViewController9.index=8;
[self presentModalViewController:self.level2ViewController9 animated:true];
}
-(IBAction)showChild10Action:(id)sender{
self.level2ViewController10.index=9;
[self presentModalViewController:self.level2ViewController10 animated:true];
}
@end
ChildViewController.h
#import <UIKit/UIKit.h>
@interface ChildViewController : UIViewController
@property(nonatomic,weak) IBOutlet UIImageView *image1;
@property NSInteger index;
-(IBAction)closeAction:(id)sender;
@end
ChildViewController.m
#import "ChildViewController.h"
@interface ChildViewController ()
@end
@implementation ChildViewController
@synthesize image1;
@synthesize index;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
if(self.index==0)
[self.image1 setImage:[UIImage imageNamed:@"IMG1.JPG"]];
if(self.index==1)
[self.image1 setImage:[UIImage imageNamed:@"IMG2.JPG"]];
if(self.index==2)
[self.image1 setImage:[UIImage imageNamed:@"IMG3.JPG"]];
if(self.index==3)
[self.image1 setImage:[UIImage imageNamed:@"IMG4.JPG"]];
if(self.index==4)
[self.image1 setImage:[UIImage imageNamed:@"IMG5.JPG"]];
if(self.index==5)
[self.image1 setImage:[UIImage imageNamed:@"IMG6.JPG"]];
if(self.index==6)
[self.image1 setImage:[UIImage imageNamed:@"IMG7.JPG"]];
if(self.index==7)
[self.image1 setImage:[UIImage imageNamed:@"IMG8.JPG"]];
if(self.index==8)
[self.image1 setImage:[UIImage imageNamed:@"IMG9.JPG"]];
if(self.index==9)
[self.image1 setImage:[UIImage imageNamed:@"IMG10.JPG"]];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
-(IBAction)closeAction:(id)sender{
[self dismissModalViewControllerAnimated:true];
}
使用乐器时,我得到了以下观察结果:
内存分配工具显示了我期望看到的内容:显示子视图控制器时上升的总分配,当子视图被解除时下降
然而,活动指示器正在讲述一个不同的故事,每个presentModalViewController都会增加实际内存,而在解除它们时不会减少
答案 0 :(得分:1)
我最终从Apple那里得到了答案:
您的“大型资源”恰好是您已加载缓存的图片 via + imageNamed:。因为它们是缓存加载的,所以它们是免除的 从自动清理。通常只生成内容 -drawRect:或Core Animation自动在此处发布。因为你的观点继续存在,他们继续持有 引用这些缓存的图像,我们无法在内存中清除它们 警告
看起来缓存资源不是文档中提到的自动清理的一部分,这些资源只有在停止被引用时才会被释放。
答案 1 :(得分:0)
听起来你某处有泄漏。即使系统没有释放这些视图,在你提供了所有10个子控制器之后,内存使用也应该最大化。如果内存使用不受限制地增长,那么您的子控制器可能会放弃他们的视图(因此每次出现时都会创建新视图),但视图不会被释放 - 过度保留情况的典型症状。尝试将子控制器的数量减少到两个,看看最终是否会发生同样的事情。或者,使用仪器寻找泄漏。
更新: -[UIImage imageNamed]
因永不释放其加载的图片而闻名 - 这可能是您内存增长的原因。尝试使用不同的方法加载图像,或者根本不加载图像(因为它们对实验并不重要)。
答案 2 :(得分:0)
而不是使用imageNamed:
使用initWithContentsOfFile
。
例如:
__weak NSString *filePath = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"];
self.imageView.image = [[UIImage alloc] initWithContentsOfFile:filePath];
由于正在使用alloc
方法,GC正在标记此对象。您甚至可以标记filePath
字符串进行GC清理。