【问题标题】:How do I load xibs by reusing a single viewcontroller and handle the memory warnings?如何通过重用单个视图控制器来加载 xib 并处理内存警告?
【发布时间】:2025-11-30 17:45:02
【问题描述】:

我正在为 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

这就是关卡的启动方式。 Game1View.m

@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

MainGameAppDelegate.m

@implementation MainGameAppDelegate
@synthesize window;
@synthesize viewController;

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

目前,当我不断在视图之间切换然后应用程序崩溃时,我会收到内存警告。 我的问题是,这是加载这些视图的正确方法吗?我已经发布了在游戏生命周期内分配的所有内容,现在我对占用内存的内容感到茫然。任何帮助将不胜感激。

【问题讨论】:

    标签: objective-c ios memory-management memory-leaks uiviewcontroller


    【解决方案1】:

    您没有正确发布游戏视图,因为您的代码实际上会在调用 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) {
    

    另外,您将视图控制器命名为“视图”会造成混淆。考虑给它们起更具描述性的名称,例如 xxxController。

    编辑 1:

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

    【讨论】:

    • 感谢您的快速回复。我想你的意思是 [currentView.view removeFromSuperview];但如果我在 [currentView release] 之​​前添加它;它只会导致我的一个 xib 在解除分配时出现 EXC_BAD_ACCESS。
    • 由于您之前已经添加了子视图,因此必须通过 removeFromSuperview 删除视图是正常的。尝试打开 XCode 的僵尸来查看额外释放的位置。
    最近更新 更多