0

So I've been using this tutorial to implement a sliding menu on my iOS app. However, when I try to hit the home cell button, the home controller refreshes as it, from my understanding, is placing another version of the controller on top of the old one. I'm building a game so you can see why this situation is not ideal--essentially, it is creating a new game each time the user uses the slide out menu. Is there anyway to prevent this refresh from happening or an alternate possible workaround?

Kyle Bachan
  • 1,053
  • 2
  • 15
  • 33
  • 1
    https://github.com/timsearle/RUMSlidingMenu This is a basic slide-out menu, giving you the minimal functionality, controllers are retained in memory and not reloaded when the menu is accessed – Tim May 08 '14 at 21:57
  • Interesting. I'll try this out and see! Thanks! – Kyle Bachan May 09 '14 at 03:25

1 Answers1

1

Based off what the tutorial is telling you, a segue is performed for each cell item in the menu. What you should do to prevent reloading of an already present View controller is perform the segue in didSelectRowAtIndexPath:, except do a check to see if the current view controller is equal to the one you selected. You should make all of the possible view controllers properties of the menu controller and have the menu controller be the root controller. This way you can detect if the last view controller was the selected one. On the controller that manages the menu in the delegate method didSelectRowAtIndexPath:, add this:

In menuController.h

@property (retain, nonatomic) OneViewController *thatViewController;

In menuController.m's didSelectRowForIndexPath:

NSArray *segueIdentifiers = @[@"firstSegueID",@"secondSegueID",...];//list of all segues possible in order matching the rows, so row0 would associate to the firstSegueID
if ([segueIdentifiers objectAtIndex:indexPath.row] isEqualToString:@"firstSegueID"])
{
    BOOL isInstantiated;
    isInstantiated = NO;
    if (self.thatViewController == nil) //or some way to check if it was already instantiated like testing a property of the controller
    {
        self.thatViewController = [[OneViewController alloc] init]; //or whatever init class method you like
        [self.thatViewController.property setThemHere];

        isInstantiated = YES;
    }

    [self presentViewController:self.thatViewController animated:YES completion:^{NSLog(@"presented that view controller, was reloaded: %@",isInstantiated);}];
}

EDIT1: So basically, instantiate the controller once:

Then place your object instantiations in proper locations in the oneViewController.m. For instance, objects you do not want to be volatile (which I am assuming is everything on the home controller) should be allocated and initialized here. This will require you to move over most of your UI mechanics to programming and away from story board. I believe when you perform a segue, it will allocate and create a new view controller and then run performSegueWithIdentifier:animated:.

EDIT2: I just realized I mistyped my code, they should now contain the latest revision, I apologize for the confusion.

EDIT3: If you still want to retain the way the method slides over, I am not too particular on animated presenting and dismissing view controllers. However, the same logic can be applied by just instantiating it strictly by doing the method from this post. If you dont want to bother:

if (! self.thatViewController) {
    self.thatViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"HomeViewController"]; // set this property in the story board
}

Then you can perform the segue without it allocating a whole new controller.

Community
  • 1
  • 1
Michael Lorenzo
  • 628
  • 10
  • 20
  • What does OneViewController represent? I'm assuming that's the name of the Home controller I'm trying not to reload. I understand the method you're using here but I'm having trouble implementing it. Firstly, Objective-C doesn't allow me to call .id on the thatViewController variable. Also, if we skipped the segue aspect, wouldn't the menu slider still remain open after we clicked the cell. Secondly, what would happen if we went to a different menu option and then back to home? I believe the home controller would still get refreshed in that case. – Kyle Bachan May 10 '14 at 03:56
  • What does OneViewController represent? It represents the controller you do not want to be reset, so yes the home controller in this case. What do you mean does not let you call the id? View Controllers can have an id property that lets them be identified against other objects. You would have allocated and initialized the home view controller already, and it would be a property of the menu view controller, so you could reference it specifically with `self.homeViewController`. There is also `presentViewController:animated:` that is accessible to managing views.-Continued onto the next comment – Michael Lorenzo May 10 '14 at 04:20
  • Essentially, you could keep the same view controller without destroying data on it or resetting it by just managing how you initiate objects and add them as subviews to the controller. For instance if you created objets in the `viewWillAppear:` class method of the home view controller, then all your properties would be reset again as opposed to in `viewDidLoad`, which would only get called the first time you load the view controller and should contain the data and objects that you dont want to have reset. – Michael Lorenzo May 10 '14 at 04:25
  • Ok--starting to get clearer. Where exactly do we initialize the lastViewController variable? We need to set that to the current controller id right? (otherwise, it will skip to the second if statement every time?) I'm not sure if I quite understand your edit--should I be running that if statement in the same didSelectRowForIndexPath method? Also, in my home controller--currently most stuff is in the viewdidload method. So you're saying there's a better place to put these so they aren't call upon each viewdidload? – Kyle Bachan May 10 '14 at 04:43
  • I just fixed the code so that it makes more sense. maybe that helps? Basically you won't be able to use the `performSegueWithIdentifier:animated:` since it may reallocate and load the view controller, releasing it from memory everytime it leaves the view. And then in your home view controller, in the method that responds to an event where you want to view the home view controller again, you could call `dismissViewControllerAnimated:completion:` – Michael Lorenzo May 10 '14 at 04:45
  • Oh ok, I see what's going on now. One thing--I am getting a crash on this line: "[self presentViewController:self.thatViewController animated:YES completion:^{NSLog(@"presented that view controller, was reloaded: %@",isInstantiated);}];" The preceding code does stop the home menu from loading if it's already selected, but I suppose I would need to manually trigger the slider closed. It doesn't go to the home controller if I'm currently on a different menu item though. – Kyle Bachan May 10 '14 at 04:59
  • What is the crash error? That NSLog logic may be bad I am writing this on the fly. Could you also describe what you mean by doesn't go to the home controller if you are on a different one. Like you are on, say settings view controller and you wanted to go back to the home one? – Michael Lorenzo May 10 '14 at 05:13
  • This is the error: "*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'" Also, yeah that's what I mean. So if I select another option in the menu slideout and then try to go back to home, nothing will happen. – Kyle Bachan May 10 '14 at 05:20
  • Check your code in your init for the new view controller. [also this](http://stackoverflow.com/a/17031777/2584565). Ah! So for your error what is happening is that you are performing a segue to another view controller and the performing controller is released from memory. That way when you go back, all the properties will be their un-initialized state. If we can prevent the view controllers from being released after the segue, we win. let me think about this for a bit. – Michael Lorenzo May 10 '14 at 05:29
  • 1
    Oh right, that makes sense. I'm wondering if I should perhaps consider saving stuff to core data and then I could potentially avoid properties getting refreshed in the viewdidload. Anyways, I am needing to crash--will look again in the morning. Thanks so much for your help so far! – Kyle Bachan May 10 '14 at 05:34
  • Yes core data would be a great way to basically save the machine state of the controller and then reload again when you need it, however I will continue to think of a way to do this where you would not need to repeatedly initialize every time. This could be prove costly, especially if you are loading visual elements like collection views. – Michael Lorenzo May 10 '14 at 05:36