我有一个iPhone应用程序,它基于一个explained in this link(基本上是一个使用ViewController
方法加载/删除其他视图的主displayView
)在框架中加载成功的视图。在我的应用程序中我正在使用NIB (示例链接使用编码视图),因此我的每个ViewControllers
都有其随附的笔尖。
仪器中的调试显示无泄漏,但如果我进入/离开一个部分(带有View.xib的ViewController),则nib保留在内存中,因此在几个输入/输出内存开始累积之后。
我知道nib没有被卸载,因为一个几乎是以编程方式创建的(IB中没有东西),而另一个确实在IB中创建了图像和按钮。首先加载大的,然后加载小的。您可以预期仪器的分配会减少。
我该如何防止这种情况?
我的结构如下,下面有一些评论:
`MyAppDelegate.h`
#import <UIKit/UIKit.h>
@class RootViewController;
@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
RootViewController *viewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet RootViewController *viewController;
-(void) displayView:(int)intNewView;
@end
`MyAppDelegate.m`
#import "MyAppDelegate.h"
#import "RootViewController.h"
@implementation MyAppDelegate
@synthesize window;
@synthesize viewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}
-(void) displayView:(int)intNewView {
[viewController displayView:intNewView];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
@end
此控制器处理子视图加载/删除:
`RootViewController.h`
#import <UIKit/UIKit.h>
@interface RootViewController : UIViewController {
}
- (void) displayView:(int)intNewView;
@end
`RootViewController.m`
#import "RootViewController.h"
#import "ViewController.h"
@implementation RootViewController
UIViewController *currentView;
- (void) displayView:(int)intNewView {
NSLog(@"%i", intNewView);
[currentView.view removeFromSuperview];
[currentView release];
switch (intNewView) {
case 1:
currentView = [[ViewController alloc] initWithNibName:@"View" bundle:nil];
break;
}
[self.view addSubview:currentView.view];
}
- (void)viewDidLoad {
currentView = [[ViewController alloc]
initWithNibName:@"View" bundle:nil];
[self.view addSubview:currentView.view];
[super viewDidLoad];
}
- (void)dealloc {
[currentView release];
[super dealloc];
}
@end
我会有case
与“详细信息”ViewControllers
一样多(现在我有3 case
,但这会增长到10或更多)。这种结构的目的是轻松地从应用程序的一个“部分”移动到另一个部分(NavBar控制器或TabBar控制器不适合我的特定需求)。
`ViewController.h`
// Generic View Controller Example
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController {
UIImageView *_image1;
UIImageView *_image2;
NSTimer *_theTimer;
}
@property (nonatomic, retain) IBOutlet UIImageView *image1;
@property (nonatomic, retain) IBOutlet UIImageView *image2;
@property (nonatomic, retain) NSTimer *theTimer;
@end
`ViewController.m`
#import "ViewController.h"
#import "MyAppDelegate.h"
@synthesize image1 = _image1, image2 = _image2, theTimer = _theTimer;
- (void)loadMenu {
[self.theTimer invalidate];
self.theTimer = nil;
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate displayView:2];
}
-(void)setView:(UIView*)aView {
if (!aView){
self.image1 = nil;
self.image2 = nil;
}
[super setView:aView];
}
- (void)viewDidLoad {
//some code
[super viewDidLoad];
}
- (void)viewDidUnload {
self.image1 = nil;
self.image2 = nil;
}
- (void)dealloc {
NSLog(@"dealloc called");
[self.theTimer invalidate];
[self.theTimer release];
[self.image1 release];
[self.image2 release];
[super dealloc];
}
请注意NSLog
中的dealloc
。这是被调用的(我可以在控制台中看到它)但是nib所需的内存没有被释放(仪器显示在离开一个部分时内存分配增加,因为加载了新的nib)。
任何帮助将不胜感激。我已经尝试了一百万种不同的东西,我无法卸下笔尖。
答案 0 :(得分:6)
经过一百万次尝试后,我终于遇到了this forum。
它声明:
显然,使用
imageNamed
将IB中分配的图像加载到图像视图中。imageNamed
以一种使它们无法加载的方式缓存图像。您可以使用viewDidLoad
在initWithContentsOfFile
中加载图片,然后将它们分配给视图。
在其他地方,我读过imageNamed
is the devil,所以我宁愿不让我的图像加载。
(顺便说一句,这是我正在使用的iPhone OS 3.1)
我最终的结果是将UIImageView
保留在IB中,但空值为.image
。修改后的代码类似于:
- (void)viewDidLoad {
NSString *path = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] resourcePath], @"myImageThatBeforeWasAValueinIB.jpg"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
outlet.image = image;
// do the rest of my stuff as it was
[super viewDidLoad];
}
- (void)dealloc {
outlet.image = nil;
[outlet release], outlet = nil;
[super dealloc];
}
现在一切都像魅力一样!当我卸下笔尖并且出现内存警告时,内存会恢复。
如果你IBOutlets
有UIImageView
并且内存是一个值得关注的问题(我猜它总是如此),那么你可以在IB中设计你想要的所有内容以及何时连接它们到出口,删除IB中的图像参考并从代码创建它。 IB非常适合布置您的应用。我不得不通过代码完成所有这些事情,但我也找到了this nice utility that converts nibs to objective c代码,尽管我还没有测试过它。
答案 1 :(得分:0)
您是否尝试在dealloc中将出口变量设置为nil? 您正在正确实现setView方法,但是您在viewDidUnload方法中将出口变量设置为nil而不是dealloc。正如here所述,您应该按如下方式实现dealloc:
- (void)setView:(UIView *)aView {
if (!aView) { // view is being set to nil
// set outlets to nil, e.g.
self.anOutlet = nil;
}
// Invoke super's implementation last
[super setView:aView];
}
- (void)dealloc {
// release outlets and set outlet variables to nil
[anOutlet release], anOutlet = nil;
[super dealloc];
}
编辑:如果出口是UIImageViews,那么可能就是你需要做的事情
anOutlet.image = nil;
因为设置UIImage的实例图像属性应该将UIImage实例的保留计数增加1.