sebastyuiop
sebastyuiop

Reputation: 534

iPhone slide view passing variables

Right, I'm trying to make an app that has a calculation that involves a stopwatch. When a button on the calculation view is clicked a stopwatch slides in from the bottom. This all works fine, the problem I can't get my head around is how to send the recorded time back to the previous controller to update a textfield.

I've simplified the code and stripped out most irrelevant stuff.

Many thanks.

CalculationViewController.h

#import <UIKit/UIKit.h>

@interface CalculationViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {

IBOutlet UITextField *inputTxt;
}
@property (nonatomic, retain) UITextField *inputTxt;

- (IBAction)showTimer:(id)sender;
@end

CalculationViewController.m

#import "CalculationViewController.h"
#import "TimerViewController.h"

@implementation CalculationViewController

- (IBAction)showTimer:(id)sender {

   TimerViewController *timerView = [[TimerViewController alloc] init];
   [self.navigationController presentModalViewController:timerView animated:YES];
}

TimerViewController.h

#import <UIKit/UIKit.h>

@interface TimerViewController : UIViewController {

IBOutlet UILabel *time;
NSTimer *myTicker;
}

- (IBAction)start;
- (IBAction)stop;
- (IBAction)reset;
- (void)showActivity;
@end

TimerViewController.m

#import "TimerViewController.h"
#import "CalculationViewController.h"

@implementation TimerViewController

- (IBAction)start { 
myTicker = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(showActivity) userInfo:nil repeats:YES];
}

- (IBAction)stop {
[myTicker invalidate];

#Update inputTxt on calculation view here

[self dismissModalViewControllerAnimated:YES];
}

- (IBAction)reset {
time.text = @"0";
}

- (void)showActivity {
int currentTime = [time.text intValue];
int newTime = currentTime + 1;

time.text = [NSString stringWithFormat:@"%d", newTime];
}
@end

Upvotes: 0

Views: 468

Answers (1)

user121301
user121301

Reputation:

A couple of ways to do this are:

  • use NSNotificationCenter, or
  • make CalculationViewController a delegate of TimerViewController (define a protocol that CalculationViewController implements)

In both cases, the TimerViewController would notify CalculationViewController it is done and at the same time pass the data with it. So in the stop method, it would do postNotificationName:object:userInfo or call a delegate method. Then the dismiss would instead be done in CalculationViewController when it receives the notification.

EDIT:
There isn't necessarily one right way every time. Depending on the size and complexity of the app and exact requirements of the situation, some ways are better than others. The app delegate is ok for sharing data across view controllers but it's probably better to use notifications or delegates to signal events across controllers like you want to do here.

A protocol is a stricter and more self-documenting and self-contained approach than notifications but for this simple case, either one is fine.

Here's how you can implement it using a protocol/delegate approach:

TimerViewController.h:

@protocol TimerViewDelegate
-(void)timerStopped:(NSString *)timerData;
@end
@interface TimerViewController : UIViewController {
    //other ivars...
    id<TimerViewDelegate> delegate;
}
//other properties...
@property (nonatomic, assign) id <TimerViewDelegate> delegate;
//method declarations...
@end

TimerViewController.m:

@implementation TimerViewController
@synthesize delegate;
- (IBAction)stop {
    [myTicker invalidate];
    NSString *timerData = @"timer data here";
    [self.delegate timerStopped:timerData];
}
@end

CalculationViewController.h:

#import "TimerViewController.h"
@interface CalculationViewController : UIViewController 
  <UITableViewDelegate, UITableViewDataSource, TimerViewDelegate > {
    ...
}
@end

CalculationViewController.m:

- (IBAction)showTimer:(id)sender {
    TimerViewController *timerView = [[TimerViewController alloc] init];
    timerView.delegate = self;
    [self.navigationController presentModalViewController:timerView animated:YES];
    [timerView release];
}

- (void)timerStopped:(NSString *)timerData
{
    inputTxt.text = timerData;
    [self dismissModalViewControllerAnimated:YES];  
}

And here's the notification version:

CalculationViewController.m:

- (IBAction)showTimer:(id)sender {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(timerStopped:) name:@"timerStopped" object:nil];
    TimerViewController *timerView = [[TimerViewController alloc] init];
    [self.navigationController presentModalViewController:timerView animated:YES];
    [timerView release];
}
- (void)timerStopped:(NSNotification*)notification
{
    NSString *timerData = [[notification userInfo] objectForKey:@"timerData"];
    inputTxt.text = timerData;
    [self dismissModalViewControllerAnimated:YES];
}

TimerViewController.m:

- (IBAction)stop {
    [myTicker invalidate];
    NSDictionary *dict = [NSDictionary dictionaryWithObject:@"timer data here" forKey:@"timerData"];
    [[NSNotificationCenter defaultCenter] postNotificationName:@"timerStopped" object:self userInfo:dict];
}

In this very simple case, a notification looks ok to use. In either case, neither controller has to know the inner details of each other nor do they depend on a third party like the app delegate. They only have to agree on the notification name and userinfo keys. The protocol approach is even more strict but self-documenting.

Upvotes: 2

Related Questions