Objective c 如何通过重用单个viewcontroller加载XIB并处理内存警告?

Objective c 如何通过重用单个viewcontroller加载XIB并处理内存警告?,objective-c,ios,memory-management,memory-leaks,uiviewcontroller,Objective C,Ios,Memory Management,Memory Leaks,Uiviewcontroller,我正在为iPhone制作一个包含4个小游戏的游戏。每个迷你游戏都是一个独立的xib。每个游戏都有自己的菜单和游戏级别。进入主菜单,选择要加载的游戏 这就是我目前加载每个xib的方式 MainGameViewController.h @interface MainGameViewController : UIViewController { UIViewController *currentView; int currentViewId; } @property (nonato

我正在为iPhone制作一个包含4个小游戏的游戏。每个迷你游戏都是一个独立的xib。每个游戏都有自己的菜单和游戏级别。进入主菜单,选择要加载的游戏

这就是我目前加载每个xib的方式

MainGameViewController.h

@interface MainGameViewController : UIViewController {

    UIViewController *currentView;
    int currentViewId;
}

@property (nonatomic, retain) UIViewController *currentView;
- (void)displayView:(int)intNewView;
@end
MainGameViewController.m

@implementation MainGameViewController

@synthesize currentView;

- (void)viewDidLoad {
    [super viewDidLoad];
    currentView = [[LogoScreen alloc] init];
    [self.view addSubview:currentView.view];
}

- (void)displayView :(int)intNewView
{
    currentViewId = intNewView;
    currentView = nil;
    [currentView release];
    switch (intNewView) {
        case SCR_GAME1:
            currentView = [[Game1View alloc] init];
            break;
        case SCR_GAME1LEVEL:
            currentView = [[Game1LevelView alloc] init];
            break;
        case SCR_GAME2:
            currentView = [[Game2View alloc] init];
            break;
        case SCR_GAME2LEVEL:
            currentView = [[Game2LevelView alloc] init];
            break;
        case SCR_GAME3:
            currentView = [[Game3View alloc] init];
            break;
        case SCR_GAME3LEVEL:
            currentView = [[Game3LevelView alloc] init];
            break;
        case SCR_GAME4:
            currentView = [[Game4View alloc] init];
            break;
        case SCR_GAME4LEVEL:
            currentView = [[Game4LevelView alloc] init];
            break;       
        default:
            currentView = [[MainView alloc] init];
            break;
    }

    [self.view addSubview:currentView.view];
}

- (void)dealloc {
    [currentView release];
    currentView = nil;

    [super dealloc];
}

@end
@implementation Game1View

-init {
    if (self == [super init]) {

        MainGameAppDelegate *appdelegate = [[UIApplication sharedApplication] delegate];
        isSoundOn = (appdelegate.gvar.soundstate == 1);
        gamestate = GAME_STATUS_START;
    }
    return self;
}
...
...
- (void)launchgame {

    MainGameAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    appDelegate.gvar.currentId = objectid;
    [appDelegate displayView:SCR_GAME1LEVEL_GAME];

}

- (void)returnToMain {
    MainGameAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    [appDelegate displayView:SCR_MAIN];
}

@end
@implementation MainGameAppDelegate
@synthesize window;
@synthesize viewController;

- (void) displayView:(int)intNewView {
    [viewController displayView:intNewView];
}
@end
这就是这些级别的启动方式。 Game1View.m

@implementation MainGameViewController

@synthesize currentView;

- (void)viewDidLoad {
    [super viewDidLoad];
    currentView = [[LogoScreen alloc] init];
    [self.view addSubview:currentView.view];
}

- (void)displayView :(int)intNewView
{
    currentViewId = intNewView;
    currentView = nil;
    [currentView release];
    switch (intNewView) {
        case SCR_GAME1:
            currentView = [[Game1View alloc] init];
            break;
        case SCR_GAME1LEVEL:
            currentView = [[Game1LevelView alloc] init];
            break;
        case SCR_GAME2:
            currentView = [[Game2View alloc] init];
            break;
        case SCR_GAME2LEVEL:
            currentView = [[Game2LevelView alloc] init];
            break;
        case SCR_GAME3:
            currentView = [[Game3View alloc] init];
            break;
        case SCR_GAME3LEVEL:
            currentView = [[Game3LevelView alloc] init];
            break;
        case SCR_GAME4:
            currentView = [[Game4View alloc] init];
            break;
        case SCR_GAME4LEVEL:
            currentView = [[Game4LevelView alloc] init];
            break;       
        default:
            currentView = [[MainView alloc] init];
            break;
    }

    [self.view addSubview:currentView.view];
}

- (void)dealloc {
    [currentView release];
    currentView = nil;

    [super dealloc];
}

@end
@implementation Game1View

-init {
    if (self == [super init]) {

        MainGameAppDelegate *appdelegate = [[UIApplication sharedApplication] delegate];
        isSoundOn = (appdelegate.gvar.soundstate == 1);
        gamestate = GAME_STATUS_START;
    }
    return self;
}
...
...
- (void)launchgame {

    MainGameAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    appDelegate.gvar.currentId = objectid;
    [appDelegate displayView:SCR_GAME1LEVEL_GAME];

}

- (void)returnToMain {
    MainGameAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    [appDelegate displayView:SCR_MAIN];
}

@end
@implementation MainGameAppDelegate
@synthesize window;
@synthesize viewController;

- (void) displayView:(int)intNewView {
    [viewController displayView:intNewView];
}
@end
MainGameAppDelegate.m

@implementation MainGameViewController

@synthesize currentView;

- (void)viewDidLoad {
    [super viewDidLoad];
    currentView = [[LogoScreen alloc] init];
    [self.view addSubview:currentView.view];
}

- (void)displayView :(int)intNewView
{
    currentViewId = intNewView;
    currentView = nil;
    [currentView release];
    switch (intNewView) {
        case SCR_GAME1:
            currentView = [[Game1View alloc] init];
            break;
        case SCR_GAME1LEVEL:
            currentView = [[Game1LevelView alloc] init];
            break;
        case SCR_GAME2:
            currentView = [[Game2View alloc] init];
            break;
        case SCR_GAME2LEVEL:
            currentView = [[Game2LevelView alloc] init];
            break;
        case SCR_GAME3:
            currentView = [[Game3View alloc] init];
            break;
        case SCR_GAME3LEVEL:
            currentView = [[Game3LevelView alloc] init];
            break;
        case SCR_GAME4:
            currentView = [[Game4View alloc] init];
            break;
        case SCR_GAME4LEVEL:
            currentView = [[Game4LevelView alloc] init];
            break;       
        default:
            currentView = [[MainView alloc] init];
            break;
    }

    [self.view addSubview:currentView.view];
}

- (void)dealloc {
    [currentView release];
    currentView = nil;

    [super dealloc];
}

@end
@implementation Game1View

-init {
    if (self == [super init]) {

        MainGameAppDelegate *appdelegate = [[UIApplication sharedApplication] delegate];
        isSoundOn = (appdelegate.gvar.soundstate == 1);
        gamestate = GAME_STATUS_START;
    }
    return self;
}
...
...
- (void)launchgame {

    MainGameAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    appDelegate.gvar.currentId = objectid;
    [appDelegate displayView:SCR_GAME1LEVEL_GAME];

}

- (void)returnToMain {
    MainGameAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
    [appDelegate displayView:SCR_MAIN];
}

@end
@implementation MainGameAppDelegate
@synthesize window;
@synthesize viewController;

- (void) displayView:(int)intNewView {
    [viewController displayView:intNewView];
}
@end
当前,当我在视图之间切换时,会收到内存警告,然后应用程序崩溃。
我的问题是,这是加载这些视图的正确方法吗?我已经发布了在游戏生命周期内分配的所有内容,现在我对占用内存的内容感到不知所措。任何帮助都将不胜感激。

您没有正确地发布游戏视图,因为您的代码实际上会在调用release之前将currentView设置为nil,这意味着您将泄漏创建的每个游戏视图

- (void)displayView :(int)intNewView
{
    currentViewId = intNewView;
    currentView = nil;
    [currentView release];
    switch (intNewView) {
您可能希望这样做:

- (void)displayView :(int)intNewView
{
    currentViewId = intNewView;
    [currentView release];
    currentView = nil;
    switch (intNewView) {
此外,将视图控制器命名为“视图”也会令人困惑。考虑给他们更多描述性的名字,比如XXXCORDECT.

编辑1:


您还需要确保在发布旧游戏之前将其从视图层次结构中删除。在释放视图之前,先调用[currentView.view removeFromSuperview]将其删除。

您没有正确地释放游戏视图,因为在调用release之前,您的代码实际上会将currentView设置为零,这意味着您将泄漏创建的每个游戏视图

- (void)displayView :(int)intNewView
{
    currentViewId = intNewView;
    currentView = nil;
    [currentView release];
    switch (intNewView) {
您可能希望这样做:

- (void)displayView :(int)intNewView
{
    currentViewId = intNewView;
    [currentView release];
    currentView = nil;
    switch (intNewView) {
此外,将视图控制器命名为“视图”也会令人困惑。考虑给他们更多描述性的名字,比如XXXCORDECT.

编辑1:


您还需要确保在发布旧游戏之前将其从视图层次结构中删除。在释放视图之前,请先致电[currentView.view removeFromSuperview]将其删除。

感谢您的快速回复。我想你的意思是[currentView.view从SuperView移除];但如果我在[当前视图发布]之前添加该选项;这只会导致我的一个XIB在释放时具有EXC\u BAD\u访问权限。由于您以前添加了子视图,因此必须通过removeFromSuperview删除该视图是正常的。试着打开XCode的僵尸,看看额外发布的地方。谢谢你的快速回复。我想你的意思是[currentView.view从SuperView移除];但如果我在[当前视图发布]之前添加该选项;这只会导致我的一个XIB在释放时具有EXC\u BAD\u访问权限。由于您以前添加了子视图,因此必须通过removeFromSuperview删除该视图是正常的。试着打开XCode的僵尸,看看额外的发布发生在哪里。