您的位置:首页 > 其它

iPhone相机和内存警告

2013-01-07 15:56 127 查看
现在我们越来越习惯于在程序中使用相机。但是,几乎在程序每次打开相机的瞬间,我们都会收到一个“Received memory warning. Level=1”内存警告 。对于iOS来说,内存永远是稀缺资源 ,因此,在你使用iPhone的高分辨率相机时,尤其需要小心。
程序员应当重视内存警告并对之进行处理,包括:
一、在viewDidUnload方法中释放内存
从iOS3.0开始, 释放内存的代码didReceiveMemoryWarning 迁移到了viewDidUnload中,我们不用覆盖didReceiveMemoryWarning方法。 事实上有不止地方会收到内存警告,因此程序中会有两个地方存在 didReceiveMemoryWarning方法:AppDelegate 和ViewController。一般,我们选择在ViewController而不是AppDelegate中处理内存警告。
当程序收到内存警告时,程序员们就必须注意了。iOS随后会自动清理当前“无用的”内存,比如内存中那些不处于顶层的ViewController和视图。



我们一般需要在viewDidUnload方法中,释放视图中无用的对象,比如UILabel、UIButton、NSArray等:
-(void)viewDidUnload{ [super viewDidUnload]; if(ivBg)[ivBg release],ivBg=nil; if(btSend)[btSendrelease],btSend=nil; if(btUpload)[btUploadrelease],btUpload=nil; if(vwBody)[vwBodyrelease],vwBody=nil; if(backButton)[backButtonrelease],backButton=nil; if(indicator)[indicatorrelease],indicator=nil; if(imagePicker)[imagePickerrelease],imagePicker=nil; if(receiverVC)[receiverVCrelease],receiverVC=nil;}注意,我们释放的对象必须是“无用的”。这些东西可能是任何对象,比如成员对象和UI对象。关键在于怎样认识一个对象是“有用的”还是“无用的”。实际上,对于iOS来说,任何在viewDidUnload方法中释放的东西都是“无用的”。如果你有任何对象在恢复视图时会用到,那么就不要在viewDidUnload方法中释放。例如,用户在视图中的输入——一封邮件的正文,或者用户正在编辑的图片——这些东西将在当相机使用完毕,iOS准备恢复视图时显示给用户。
如果你确实不得不节省出更多的内存,那么你可以在viewDidUnload中把一些有用的东西也释放掉,前提是,当你收到内存警告时,把这些对象持久化(保存到文件)。
而有的对象,它们本来就在xib文件中存在。在iOS恢复视图时,这些东西会从xib中恢复到内存(initWithNibName->viewDidLoad)。比如按钮、图片、静态标签等UI对象。这些对象我们就可以看作是“无用的”,在viewDidUnload方法中可以毫不客气地把它们统统释放。
二、在 didReceiveMemoryWarning 方法中设置内存警告标志
现在,虽然我们已经在viewDidUnload方法中,而不用在 didReceiveMemoryWarning方法中释放对象,但didReceiveMemoryWarning方法仍然有一个用途,就是设置内存警告变量,以让程序员知道何时收到内存警告。
首先声明一个BOOL成员作为是否收到过内存警告的标志:
BOOLmaybeSetViewNil;然后在didReceiveMemoryWarning方法中:
maybeSetViewNil=YES;三、在viewDidUnload方法中,保存视图数据以便恢复
在第一步中,我们提到为了“尽可能地”为iOS腾出内存,我们可以把所有对象释放,但对于“有用的”的对象,我们应该采用必要的保存策略,比如保存到文件缓存中。
仍然在viewDidUnload方法中,加入以下代码:
NSMutableDictionary*d=[[NSMutableDictionary alloc]init]; //"in use" objects if(tfTitle){ if(tfTitle.text) [d setObject:tfTitle.text forKey:@"tfTitle.text"]; self.tfTitle=nil; } if(lbAttach){ if(lbAttach.text) [d setObject:lbAttach.text forKey:@"lbAttach.text"]; self.lbAttach=nil; } if(imageView){ if(imageView.image) { NSData* data=UIImageJPEGRepresentation(imageView.image,0.7); if (data)[d setObject:data forKey:@"imageView.image"]; } self.imageView=nil; } if(receivers){ [dsetObject:receivers forKey:@"receivers"]; [receivers release],receivers=nil; } if(selectedPeople){ [dsetObject:selectedPeople forKey:@"selectedPeople"]; [selectedPeople release],selectedPeople=nil; }[VCCachesaveToCache:d toVC:self]; [d release]; 可以看到,我们把所有“有用的”对象放到了Dictionary集合中。CCache是一个自定义类,我用它把Dictionary保存到指定文件。
四、恢复视图状态
接下来我们可以在viewDidLoad方法中恢复视图状态了:
selectedPeople=[[NSMutableArrayalloc]init]; receivers=[[NSMutableStringalloc]init]; if (maybeSetViewNil) { NSLog(@"maybe set view nil!"); NSDictionary* d=[VCCache loadCache:self]; if(d!=nil) {// status restore id obj=[d objectForKey:@"tfTitle.text"]; if(obj!=nil)tfTitle.text=(NSString*)obj; obj=[d objectForKey:@"lbAttach.text"]; if(obj!=nil)lbAttach.text=(NSString*)obj; obj=[d objectForKey:@"imageView.image"]; if(obj!=nil)imageView.image=[UIImage imageWithData:(NSData*)obj]; ⋯⋯ obj=[d objectForKey:@"receivers"]; if(obj!=nil)[receivers setString:(NSString*)obj]; obj=[d objectForKey:@"selectedPeople"]; if(obj!=nil)[selectedPeople setArray:(NSArray*)obj]; } maybeSetViewNil=NO; }注意,receivers和selectedPeople对象要在viewDidLoad方法中初始化,而不能在initWithNibName方法中初始化,否则对一个nil对象赋值是无效的。因为iOS在恢复视图时从loadView方法开始调用,而不是从initWithNibName方法(参考前面的图)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: