is it possible to not dealloc a view controller when the back button is pressed in a navigation controller?

StackOverflow https://stackoverflow.com/questions/17962040

سؤال

Here is my issue: I have a tableview with a bunch of cells. Core Data loads Task object into the cells using NSFetchedResultsController. Right now I have it so each cell has a DetailViewController, which is stored in a dictionary like so:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    DetailViewController *detailVC;
    if (![self.detailViewsDictionary.allKeys containsObject:@(indexPath.row)]){
        detailVC = [[DetailViewController alloc]initWithNibName:@"DetailViewController" bundle:nil];
        [self.detailViewsDictionary setObject:detailVC forKey:@(indexPath.row)];
    }else{
        detailVC = self.detailViewsDictionary[@(indexPath.row)];
    }
        Tasks *task = [[self fetchedResultsController] objectAtIndexPath:indexPath];
        detailVC.testTask = task;
        [[self navigationController] pushViewController:detailVC animated:YES];
}

Each DetailViewController has a timer property that gets its time interval from the Task object which correlates to the cell at any given index path in the tableview. Here is the code I have for my detail view controller:

- (void)viewDidLoad {
    [super viewDidLoad];
    [NSThread detachNewThreadSelector:@selector(startTimer:) toTarget:self withObject:nil];
}
-(IBAction)startTimer:(id)sender{
//default value of showButtonValue when first loaded is 1
    if (testTask.showButtonValue == 1) {
        [startButton setTitle:@"Start" forState:UIControlStateNormal];
        timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
        testTask.showButtonValue = 3;
    } else if (testTask.showButtonValue == 2) {
        [startButton setTitle:@"Resume" forState:UIControlStateNormal];
        [timer invalidate];
        timer = nil;
        testTask.showButtonValue = 3;
    } else if (testTask.showButtonValue == 3){
        [startButton setTitle:@"Pause" forState:UIControlStateNormal];
        timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
        testTask.showButtonValue = 2;
    }
}
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    nameTextField.text = testTask.taskName;
    [timerLabel setFont:[UIFont fontWithName:@"Arial" size:60]];
    NSUInteger seconds = (NSUInteger)round(testTask.timeInterval);
    NSString *string = [NSString stringWithFormat:@"%02u:%02u:%02u",
                        seconds / 3600, (seconds / 60) % 60, seconds % 60];
    timerLabel.text = string;
    [[self navigationItem] setTitle:[testTask taskName]];

    [timerLabel setNeedsDisplay];
    [self.view setNeedsDisplay];
}
-(void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    testTask.taskName = nameTextField.text;
}
-(void)timerAction:(NSTimer *)t
{
    if(testTask.timeInterval == 0)
    {
        if (self.timer)
        {
            [self timerExpired];
            [self.timer invalidate];
            self.timer = nil;
        }
    }
    else
    {
        testTask.timeInterval--;
    }
    NSUInteger seconds = (NSUInteger)round(testTask.timeInterval);
    NSString *string = [NSString stringWithFormat:@"%02u:%02u:%02u",
                        seconds / 3600, (seconds / 60) % 60, seconds % 60];
    timerLabel.text = string;
    NSLog(@"%f", testTask.timeInterval);
}

The timer is SUPPOSED to keep on going regardless of whether the detail view controller is currently on the screen or not. When I tap a cell for the first time, go to the detail view controller and start the timer, and then go BACK to the tableview, there is no problem and the countdown keeps on going. The PROBLEM is that if I re-tap the cell, another timer is created so the time decrements 2x as fast! Not only that, but the string which displays the remaining time doesn't update upon ViewWillAppear, it only updates the first time timerAction is called.

There are a bunch of issues, I really would appreciate some help!

هل كانت مفيدة؟

المحلول

The code you have in didSelectRowAtIndexPath, which I provided in my answer to your other question (one timer per detail view controller), does prevent the controller from being deallocated when you press the back button. It does this by keeping a reference to the detail view controller in a dictionary. I'm guessing that it's not working for you because you forgot to initialize the dictionary, so it's nil.

نصائح أخرى

I am giving my opinion even if question has been answered. Onestly, I may be wrong, but I don't think that preventing deallocation is a good idea, especially of a whole controller. In iOS, memory has to be released as soon as possible.

However, by seeing your code, I would do few things.

  • Move label creation to viewDidLoad, and update its content in viewWillAppear
  • Put your timer creation and launch within a utility class, with proper methods to start, stop, pause a given timer. The class will ensure there's only one (or more with an assigned ID) timer running, and controller can ask for it. It's not really elegant, but you can at least use the AppDelegate for this.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top