Ios UIViewController将不会被删除

Ios UIViewController将不会被删除,ios,objective-c,memory-management,uiviewcontroller,Ios,Objective C,Memory Management,Uiviewcontroller,我正在努力解决两个UIViewController之间的保留问题。视图控制器从未被删除,导致我的应用程序内存消耗不断增加 UITitleScreenViewController是我的初始视图控制器。当我从它转到UIChooseAntViewController a choose player屏幕时,我想放弃对UIITleviewController的所有权,但正如您在下面的仪器中看到的那样,控制器在转换后仍然保留: 第二个图像是保留/释放历史记录。133之前的所有条目都是在应用程序启动时发布的。

我正在努力解决两个UIViewController之间的保留问题。视图控制器从未被删除,导致我的应用程序内存消耗不断增加

UITitleScreenViewController是我的初始视图控制器。当我从它转到UIChooseAntViewController a choose player屏幕时,我想放弃对UIITleviewController的所有权,但正如您在下面的仪器中看到的那样,控制器在转换后仍然保留:

第二个图像是保留/释放历史记录。133之前的所有条目都是在应用程序启动时发布的。我相信133对和140对是由故事板segue创造的。那么,谁的责任是发布额外的释放来销毁控制器呢?我试图在我的遗嘱上设置self.view=nil,但没有达成协议

它不仅没有释放控制器,而且每次转换时都会创建控制器的新实例。例如,当我从ChooseAnt返回到Title时,它会创建另一个UITitleViewController实例

重要的是要说:

1目标方案中未勾选NSZombies标志 2我的UITitleViewController中没有任何块,我在UIChooseAntController中注释掉了所有块。事实上,这些控制器非常简单。Utitle完全是通过故事板定义的,只是一个带有背景的视图和两个执行序列的按钮

而UIChooseAnt是一个控件,它提供背景和滑动界面来显示可用字符和单选按钮。通过调用[self-PerformsgueWithIdentifier]以编程方式执行segue

3我不知道这是否重要,但分段被定义为模态,没有动画

编辑:4没有一个控制器相互引用

下面是TitleViewController的源代码

这个问题快把我逼疯了。如果有人能解释一下的话。任何事情都会有很大的帮助!谢谢

@interface SMTitleScreenViewController ()
@property (weak, nonatomic) IBOutlet UIButton *buttonPlay;
@property (weak, nonatomic) IBOutlet UIButton *buttonCamera;

- (IBAction)onButtonPlay:(id)sender;
- (IBAction)onButtonCamera:(id)sender;
@end

@implementation SMTitleScreenViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {

    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIColor* color = [UIColor colorWithRed:0.2509f green:0.1176f blue:0.0745f         alpha:1.0f];
    UIFont* font = [UIFont fontWithName:@"Jungle Roar" size:BUTTON_FONT_SIZE];

    NSString* playString = NSLocalizedString(@"Play", @"");
    NSString* cameraString = NSLocalizedString(@"Camera", @"");

    [self.buttonPlay setTitle:playString forState:UIControlStateNormal];
    [self.buttonPlay setTitle:playString forState:UIControlStateHighlighted];
    [self.buttonPlay setTitleColor:color forState:UIControlStateNormal];
    [self.buttonPlay setTitleColor:color forState:UIControlStateHighlighted];
    self.buttonPlay.titleLabel.font = font;

    [self.buttonCamera setTitle:cameraString forState:UIControlStateNormal];
    [self.buttonCamera setTitle:cameraString forState:UIControlStateHighlighted];
    [self.buttonCamera setTitleColor:color forState:UIControlStateNormal];
    [self.buttonCamera setTitleColor:color forState:UIControlStateHighlighted];
    self.buttonCamera.titleLabel.font = font;
}

- (void) viewDidDisappear:(BOOL)animated
{
    if ([self.view window] == nil)
    {
        self.view = nil;
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

    if ([self.view window] == nil)
    {
        self.view = nil;
    }
}

- (IBAction)onButtonPlay:(id)sender
{

}

- (IBAction)onButtonCamera:(id)sender
{

}
编辑:UIChooseAntViewController(根据请求)

    @interface SMChooseAntViewController ()
    @property (strong, nonatomic) UIImageView* rope;
    @property (strong, nonatomic) UIImageView* antFrontLayer;
    @property (strong, nonatomic) UIImageView* antBackLayer;
    @property (strong, nonatomic) NSArray* antFrontImages;
    @property (strong, nonatomic) NSArray* antBackImages;
    @property (strong, nonatomic) NSArray* antNameImages;
    @property (strong, nonatomic) UIButton* leftButton;
    @property (strong, nonatomic) UIButton* rightButton;
    @property (strong, nonatomic) UIButton* confirmButton;
    @property (nonatomic) NSUInteger selectedAntID;
    @property (strong, nonatomic) UIImage* radioImageHighlighted;
    @property (strong, nonatomic) UIImage* radioImage;
    @property (strong, nonatomic) NSMutableArray* radioViews;
    @property (weak, nonatomic) IBOutlet UILabel *antDescriptionLabel;
    @property (weak, nonatomic) IBOutlet UIImageView *antDescriptionBG;
    @property (strong, nonatomic) UIImageView* antNameView;
    @property (strong, nonatomic) UISwipeGestureRecognizer* leftSwipeRecognizer;
    @property (strong, nonatomic) UISwipeGestureRecognizer* rightSwipeRecognizer;

    - (void) onArrowButton:(id)sender;
    - (void) onConfirmButton:(id)sender;
    - (void) respondToSwipe:(UISwipeGestureRecognizer*)recognizer;
    @end

    @implementation SMChooseAntViewController

    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self)
        {
            // Custom initialization
        }
        return self;
    }

    - (void)viewDidLoad
    {
        [super viewDidLoad];

        CGSize screenSize = [[UIScreen mainScreen] bounds].size;

        // Needed to come in between front and back player image layers
        UIImage* ropeImage = [UIImage imageNamed:ROPE_IMAGE_PATH];
        self.rope = [[UIImageView alloc] initWithImage:ropeImage];
        self.rope.center = CGPointMake(screenSize.width / 2.0f, ropeImage.size.height / 2.0f);

        UIColor* brownColor = [UIColor colorWithRed:0.2509f green:0.1176f blue:0.0745f alpha:1.0f];
        self.antDescriptionLabel.textColor = brownColor;
        self.antDescriptionLabel.numberOfLines = 0;

        NSArray* antNames = [SMProfile antNames];

        // Cache available Player Views in a NSArray
        UIImage* frontImages[MAX_AVAILABLE_ANTS];
        UIImage* backImages[MAX_AVAILABLE_ANTS];
        UIImage* nameImages[MAX_AVAILABLE_ANTS];
        for (NSUInteger i = 0; i < MAX_AVAILABLE_ANTS; ++i)
        {
            NSString* antName = [antNames objectAtIndex:i];

            frontImages[i] = [SMImage imageNamed:[NSString stringWithFormat:@"%@_title_front.png", antName]];
            backImages[i] = [SMImage imageNamed:[NSString stringWithFormat:@"%@_title_back.png", antName]];
            nameImages[i] = [SMImage imageNamed:[NSString stringWithFormat:@"%@_name.png", antName]];
        }

        self.antFrontImages = [NSArray arrayWithObjects:frontImages[0], frontImages[1], frontImages[2], nil];
        self.antBackImages = [NSArray arrayWithObjects:backImages[0], backImages[1], backImages[2], nil];
        self.antNameImages = [NSArray arrayWithObjects:nameImages[0], nameImages[1], nameImages[2], nil];

        // Load Selected player from profile
        SMProfile* profile = [SMProfile mainProfile];
        self.selectedAntID = profile.antID.unsignedIntegerValue;
        self.antFrontLayer = [[UIImageView alloc] initWithImage:[self.antFrontImages objectAtIndex:self.selectedAntID]];
        self.antBackLayer = [[UIImageView alloc] initWithImage:[self.antBackImages objectAtIndex:self.selectedAntID]];

        self.antNameView = [[UIImageView alloc] initWithImage:[self.antNameImages objectAtIndex:self.selectedAntID]];
        self.antNameView.center = CGPointMake(screenSize.width / 2.0f, self.antDescriptionBG.frame.origin.y);

        NSString* antDescriptionKey = [NSString stringWithFormat:@"AntDescription%lu", (unsigned long)self.selectedAntID];
        self.antDescriptionLabel.text = NSLocalizedString(antDescriptionKey, @"");
        self.antDescriptionLabel.numberOfLines = 0;
        self.antDescriptionLabel.adjustsFontSizeToFitWidth = YES;

        self.antFrontLayer.center = CGPointMake(screenSize.width / 2.0f, ropeImage.size.height * 0.75f);
        self.antBackLayer.center = self.antFrontLayer.center;

        // Here a perform button creation, loading and positioning
        // No blocks are being called

        // add Target to buttons
        [self.leftButton addTarget:self action:@selector(onArrowButton:) forControlEvents:UIControlEventTouchUpInside];
        [self.rightButton addTarget:self action:@selector(onArrowButton:) forControlEvents:UIControlEventTouchUpInside];
        [self.confirmButton addTarget:self action:@selector(onConfirmButton:) forControlEvents:UIControlEventTouchUpInside];

        // Create and configure SwipeRecognizers    
        self.leftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(respondToSwipe:)];
        self.leftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
        [self.view addGestureRecognizer:self.leftSwipeRecognizer];

        self.rightSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(respondToSwipe:)];
        self.rightSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
        [self.view addGestureRecognizer:self.rightSwipeRecognizer];

        // Here a create a custom page control scheme. I load two radio button images
        // create views and add them to the root view node.

        // Add remaining view to the hierarchy
        [self.view addSubview:self.antBackLayer];
        [self.view addSubview:self.rope];
        [self.view addSubview:self.antFrontLayer];
        [self.view addSubview:self.confirmButton];
        [self.view bringSubviewToFront:self.antDescriptionBG];
        [self.view bringSubviewToFront:self.antDescriptionLabel];
        [self.view addSubview:self.leftButton];
        [self.view addSubview:self.rightButton];
        [self.view addSubview:self.antNameView];

        [self.view bringSubviewToFront:[self.radioViews objectAtIndex:0]];
}

- (void) viewDidDisappear:(BOOL)animated
{
    if ([self.view window] == nil)
    {
        self.rope = nil;
        self.antFrontLayer = nil;
        self.antBackLayer = nil;
        self.antFrontImages = nil;
        self.antBackImages = nil;
        self.antNameImages = nil;
        self.leftButton = nil;
        self.rightButton = nil;
        self.confirmButton = nil;
        self.radioImageHighlighted = nil;
        self.radioImage = nil;
        self.radioViews = nil;
        self.antNameView = nil;
        self.leftSwipeRecognizer = nil;
        self.rightSwipeRecognizer = nil;

        self.view = nil;
    }
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

    if ([self.view window] == nil)
    {
        self.view = nil;
    }
}

- (void)onArrowButton:(id)sender
{
    UIButton* button = (UIButton*)sender;
    NSInteger direction = button.tag;

    // if on boundaries do nothing (first ant selected and swipe left or last ant selected and swipe right)
    if ((self.selectedAntID == 0 && direction == -1) || (self.selectedAntID == (MAX_AVAILABLE_ANTS - 1) && direction == 1))
    {
        return;
    }

    // Update Radio Buttons. Unselect previous and select next.
    UIImageView* currRadio = [self.radioViews objectAtIndex:self.selectedAntID];
    currRadio.image = self.radioImage;

    self.selectedAntID = (self.selectedAntID + MAX_AVAILABLE_ANTS + direction) % MAX_AVAILABLE_ANTS;

    UIImageView* nextRadio = [self.radioViews objectAtIndex:self.selectedAntID];
    nextRadio.image = self.radioImageHighlighted;

    self.antFrontLayer.image = [self.antFrontImages objectAtIndex:self.selectedAntID];
    self.antBackLayer.image = [self.antBackImages objectAtIndex:self.selectedAntID];
    self.antNameView.image = [self.antNameImages objectAtIndex:self.selectedAntID];

    // here I was issuing some block to perform the swipe animation for the ant image views. I commented them and I'm just replacing the images now (3 lines above)
}

- (void)onConfirmButton:(id)sender
{
    // Save player choice to profile and perform segue
    SMProfile* profile = [SMProfile mainProfile];
    profile.antID = [NSNumber numberWithUnsignedInt:self.selectedAntID];
    [profile save];

    [self performSegueWithIdentifier:@"chooseAntToStageSelect" sender:self];
}

- (void) respondToSwipe:(UISwipeGestureRecognizer *)recognizer
{
    // forward swipe to onArrowButton message
    if (recognizer.direction == UISwipeGestureRecognizerDirectionLeft)
    {
        [self onArrowButton:self.rightButton];
    }
    else if (recognizer.direction == UISwipeGestureRecognizerDirectionRight)
    {
        [self onArrowButton:self.leftButton];
    }
}

@end

当从A显示B视图控制器时,A不会释放,因为A是presentingViewController请参阅sdk文档


或者,如果A、B是导航控制器的子视图控制器,则A存储在推送堆栈中,推送到B时,该堆栈不会被删除。

您将视图控制器推送到堆栈中,因此,直到最后一个视图控制器未弹出,控制器才会被释放

要深入了解对孩子的依赖,请阅读下面的文章

我相信这会有帮助的


您是否在UITitleScreenViewController中创建了任何UIChooseAntViewController属性?没有。实际上我忘了提到这一点。没有一个控制器相互引用。UITitleScreenViewController代码已按原样发布。能否发布uIChooseAntViewController的代码??我认为你保留了那里的任何对象,因此它不是releasedOk,我只是将它添加到原始帖子中。我对几个部分进行了注释,以使其更小。谢谢你看。丹云谢谢你的领导。看起来这正是发生的事情,UIChooseAntViewController通过其modalParentViewController属性持有对title controller的引用,而UITitle持有一个modalChild,尽管我仍然不知道如何修复它。可能我使用了错误的转换。我不希望这些视图被堆叠,我希望它们彼此完全独立。比如,当我从菜单转到游戏屏幕时。我想释放所有与菜单相关的资源并加载游戏资源。我该怎么做?谢谢?你可以这样做:第1步:显示目标视图控制器B。第2步:当A消失时,A将B设置为当前窗口的根视图控制器。看起来这正是发生的事情。正如我所指的丹云,我需要从一种观点过渡到另一种观点,并且在这两者之间不保持任何关系。我该怎么做?