NSTimer link with UIPickerView iOS - ios

I have a UIPickerView with an array in one view controller and an NSTimer in another, i am trying to:
1) link the picker array to NSTimer so a user selects a time on the picker for image to self destruct
2) show time remaining in UILabel so seconds the user selects going down to 0. (ex. select 2 from picker label shows 2 then 1 then 0 and image destucts)
one vc.h
#property (strong, nonatomic) IBOutlet UIPickerView *timePicker;
#property (nonatomic, strong) NSArray *pickerData;
one vc.m
- (void)viewDidLoad {
[super viewDidLoad];
self.pickerData = #[#1,#2,#3,#4,#5,#6,#7];
self.timePicker.dataSource = self;
self.timePicker.delegate = self;
}
- (void) viewWillAppear:(BOOL)animated {
[self.textField setText:self.userText];
}
-(long)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
-(long)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return self.pickerData.count;
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
[self.pickerData objectAtIndex:[self.timePicker selectedRowInComponent:0]];
}
two vc.h
#property (weak, nonatomic) IBOutlet UILabel *timeLabel;
#property (nonatomic, assign) int seconds;
two vc.m
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[NSTimer scheduledTimerWithTimeInterval:7 target:self selector:#selector(timeout)
userInfo:nil repeats:NO];
[NSTimer scheduledTimerWithTimeInterval:self.seconds target:self selector:#selector(setTimeToLabel) userInfo:nil repeats:NO];
}
-(void)timeout
{
// pops to root view
}
- (void)setTimeToLabel
{
self.seconds = self.seconds - 1;
self.timeLabel.text = [NSString stringWithFormat:#"%d", self.seconds];
}
the NSTimer does not respond to the self.seconds and does not pick up the user input from the UIPicker.
any ideas as to how I can link the picker to the timer so that the timer responds to the seconds the user selects in the picker and display the remaining seconds in the label??
my prepareforsegue method below:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.destinationViewController isKindOfClass:[oneViewController class]]) {
oneViewController * ovc = (oneViewController*)segue.destinationViewController;
ovc.array = //whatever;
}
if ([segue.destinationViewController isEqual:#"secondVC"]) {
NSInteger row = [self.timePicker selectedRowInComponent:0];
twoViewController *tvc = [segue destinationViewController];
tvc.seconds = [[self.pickerData objectAtIndex:row] intValue];
}
}
what can be the issue with it, the onviewcontroller method works, whatever i pass it works, but for the tvc.seconds nothing is passed to it.

You are creating a new instance of the controller rather than the actual one that would be used. You should be using the prepareForSegue method to do this, and get a reference to the destinationViewController, like so:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqual: #"nextScreen"]) {
NSInteger row = [self.timePicker selectedRowInComponent:0];
SecondViewController *tvc = [segue destinationViewController];
tvc.seconds = [[self.pickerData objectAtIndex:row] intValue];
}
}
// First View Controller
//.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *textField;
#property (weak, nonatomic) IBOutlet UIPickerView *timePicker;
#property (nonatomic, strong) NSArray *pickerData;
#property (weak, nonatomic) IBOutlet UIButton *next;
#end
//.m
#import "ViewController.h"
#import "SecondViewController.h"
#interface ViewController () <UIPickerViewDataSource, UIPickerViewDelegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.pickerData = #[#1,#2,#3,#4,#5,#6,#7];
self.timePicker.dataSource = self;
self.timePicker.delegate = self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return self.pickerData.count;
}
- (NSString*)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [NSString stringWithFormat: #"%#", self.pickerData[row]];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
[self.pickerData objectAtIndex:[self.timePicker selectedRowInComponent:0]];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqual: #"nextScreen"]) {
NSInteger row = [self.timePicker selectedRowInComponent:0];
SecondViewController *tvc = [segue destinationViewController];
tvc.seconds = [[self.pickerData objectAtIndex:row] intValue];
}
}
#end
// SecondViewController
//.h
#import "ViewController.h"
#interface SecondViewController : ViewController
#property (nonatomic) int seconds;
#property (weak, nonatomic) IBOutlet UILabel *timeLabel;
#end
//.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[NSTimer scheduledTimerWithTimeInterval:7 target:self selector:#selector(timeout)
userInfo:nil repeats:NO];
[NSTimer scheduledTimerWithTimeInterval:self.seconds target:self selector:#selector(setTimeToLabel) userInfo:nil repeats:NO];
}
-(void)timeout
{
// pops to root view
}
- (void)setTimeToLabel
{
self.seconds = self.seconds - 1;
self.timeLabel.text = [NSString stringWithFormat:#"%d", self.seconds];
}
#end

Related

Cannot reference delegate protocols in implimentation

I have a UIViewController with a UIPickerView that creates a string that I want to pass along to my RootViewController (BL_MainViewController).
My tactic was to use the delegate pattern but I can't figure out where I'm going wrong here. If my RootViewController is created using a Storyboard, how do I tell it BL_MainViewController.BL_SetTimerViewController = self and where do I set that in the implementation (guess:ViewDidLoad)?
BL_SetTimerViewController.h (the child VC presented by modal segue in IB)
#protocol BL_SetTimerViewControllerDelegate
-(void) updateLabelWithString:(NSString *)string;
#end
#interface BL_SetTimerViewController : UIViewController{
... // some ivars
}
#property (assign, nonatomic) id <BL_SetTimerViewControllerDelegate> delegate;
#end
BL_SetTimerViewController.m
#implementation BL_SetTimerViewController
...
#synthesize delegate;
...
- (IBAction)setTimerAndDismissViewController:(id)sender {
// does some stuff, then:
[self.delegate updateLabelWithString:#"TEST"];
[self dismissViewControllerAnimated:YES completion:nil];
}
BL_MainViewController.h (The Root VC)
#import "BL_SetTimerViewController.h"
#interface BL_MainViewController : UIViewController <BL_SetTimerViewControllerDelegate>{
...
}
#end
BL_MainViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// do some stuff here
// presumably also assign the delegate protocol?
}
-(void)updateLabelWithString:(NSString *)string {
self.pLabel.text = string;
}
In your BL_MainViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.pLabel.text=GlobleSting;
}
-(void)updateLabelWithString:(NSString *)string {
GlobleSting = string; //declare in .h file
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"YoursegueIdentifir"]) {
BL_SetTimerViewController *settimerVC =
segue.destinationViewController;
settimerVC.delegate = self;
}
}
Super simple test app for delegate(note that many thing are left out as it's quickly thrown together), this works for me.(note that delegate is weak, not assign. If you are targeting iOS 5+, use weak for delegates)
SimpleProtocol.h
#protocol SimpleProtocol <NSObject>
- (void)updateText:(NSString *)text;
#end
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#import "SimpleProtocol.h"
#interface ViewController ()<SimpleProtocol>
#property (nonatomic, weak) IBOutlet UILabel *label;
#end
#implementation ViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SecondViewController *vc = (SecondViewController *)segue.destinationViewController;
vc.delegate = self;
}
- (void)updateText:(NSString *)text
{
self.label.text = text;
}
#end
SecondViewController.m
#import "SimpleProtocol.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(timerFire:) userInfo:nil repeats:NO];
}
- (void)timerFire:(NSTimer *)timer
{
NSString *text = [NSString stringWithFormat:#"Test %#", #(arc4random())];
[self.delegate updateText:text];
[self.navigationController popViewControllerAnimated:YES];
}
#end

Can't change label.text and don't know why

I want to change label.text but when I do it and check it with a NSLog it returns me a (null).
Here's my code:
NextViewController.h
#interface NextViewController (){
NSTimer *timerTen;
NSInteger countDown;
NSString *timer;
}
#end
#implementation NextViewController
static UILabel *lblTest;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)startCountDown{
countDown = 10;
timerTen = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(dismissView) userInfo:nil repeats:YES];
}
-(void)dismissView{
timer = [NSString stringWithFormat:#"%ld", (long)countDown];
_lbl_countDown.text = timer;
NSLog(#"\nCountDown: %#\n", self.lbl_countDown.text);
countDown--;
if (countDown <= 0) {
SectionViewController *sectionView = [[SectionViewController alloc] init];
[sectionView.presentedViewController dismissViewControllerAnimated:YES completion:nil];
}
}
Then I have a XIB file with a label and more things, so I've used a prop right there in the .h to change it from other classes, but I can't change it.
NextViewController.h
#import <UIKit/UIKit.h>
#interface NextViewController : UIViewController
#property (strong, nonatomic) IBOutlet UILabel *lbl_section;
#property (strong, nonatomic) IBOutlet UILabel *lbl_nextSection;
#property (strong, nonatomic) IBOutlet UILabel *lbl_countDown;
-(void)startCountDown;
#end
Hope anyone can help me cause I don't know what is happening here.
Thanks.
Call your method in ViewDidLoad or ViewWillAppear
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self startCountDown]
}
OR
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self startCountDown]
}
Try to call the function first using [self startCountDown] in the ViewDidLoad method
if the problem persist:
Try to use this : [_lbl_count setText#"myText"];
In the Identity Inspector, click on the label uncheck the 'Static Text' and check 'Enabled' and 'User Interaction Enabled'
Finally check that your variable timer is not null after your initialization.
timer = [NSString stringWithFormat:#"%ld", (long)countDown];
Hope that will be helpfull
I wrote this code to use a button tap to start a countdown from 10 to a segue:
In my h:
#property (strong, nonatomic) IBOutlet UILabel *countdownCounter;
#property (strong, nonatomic) IBOutlet UIButton *countdownStarter;
In my m:
static NSTimer *timer;
static int remainingCounts;
.
.
-(void)countDown
{
if (--remainingCounts == 0)
{
[timer invalidate];
timer = nil;
[self performSegueWithIdentifier:#"FromStartToBalancer" sender:self];
}
else
{
NSString * holdText = [NSString stringWithFormat:#"%d", remainingCounts];
[self.countdownCounter setText:holdText];
}
}
- (IBAction)goToBalancerPressed:(UIButton *)sender
{
self.countdownStarter.userInteractionEnabled = NO;
self.countdownStarter.alpha = .3;
remainingCounts = 10;
timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(countDown)
userInfo:nil
repeats:YES];
}

Add up all values in NSMutableArray and multiply by value depending on Plain Segmented Control

What i want to do is multiply the latest NSMutableArray array entry (entered using a UITextField) by 3 when Moderate intensity is selected using the Plain Segmented Control and 6 when vigorous is selected and then display the total value of all entries in the array after the multiplications have occurred. E.g. If there User selects Moderate using the Plain Segmented Control and enters 120 in the UITextField, I need a value of 360 to be displayed and for that value to increment as more entries are made.
So far I'm storing the array values in a table like below which works fine.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"SecondViewControllerSegue"]) {
SecondViewController *secondViewController
= [segue destinationViewController];
//secondViewController.infoRequest = self.nameField.text;
NSString* style = (styleSeg.selectedSegmentIndex == 0) ? #"Moderate intensity for" : #"Vigourous intensity for";
[activities addObject:[[NSString alloc]initWithFormat:#"Your activity: %#", self.activityField.text]];
secondViewController.activities = activities;
[activities addObject:[[NSString alloc]initWithFormat:#"%#: %# minutes", style, self.nameField.text]];
secondViewController.activities = activities;
}
}
I just can't seem to multiply and output the values. I've been playing around with something like
if(styleseg.selectedSegmentIndex == 0){
3x(what the user entered in duration)
}
if(styleseg.selectedSegmentIndex == 1){
6x(what the user entered in duration)
}
And a loop attempting to add up the total values in the array which is just outputting 0.
int result = 0;
for(int i=0;i<[activities count];i++)
result += [[activities objectAtIndex:i] intValue];
NSLog(#"result = %d", result);
I'm just having trouble blending the two together to do what I want. Any help is greatly appreciated.
NEW EDIT
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
IBOutlet UIView *nameView;
IBOutlet UITextField *nameField;
IBOutlet UITextField *activityField;
IBOutlet UISegmentedControl *styleSeg;
}
#property UIView *nameView;
#property UITextField *nameField;
#property UITextField *activityField;
#property (strong,nonatomic) NSMutableArray *activities;
- (IBAction)submitButtonTapped:(id)sender;
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "SecondViewController.h"
#import "MyActivity.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize nameView;
#synthesize nameField;
#synthesize activityField;
#synthesize activities;
- (void)viewDidLoad
{
[super viewDidLoad];
activities = [[NSMutableArray alloc] init];
//activityName = [[NSMutableArray alloc] init];
}
-(void)viewWillAppear:(BOOL)animated
{
self.nameField.text = #"";
self.activityField.text = #"";
styleSeg.selectedSegmentIndex = 0;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)submitButtonTapped:(id)sender {
NSLog(#"The submit button was clicked.");
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"SecondViewControllerSegue"]) {
SecondViewController *secondViewController
= [segue destinationViewController];
secondViewController.infoRequest = self.nameField.text;
/* This was my initial code as in the intial question
NSString* style = (styleSeg.selectedSegmentIndex == 0) ? #"Moderate intensity for" : #"Vigourous intensity for";
[activities addObject:[[NSString alloc]initWithFormat:#"Your activity: %#", self.activityField.text]];
secondViewController.activities = activities;
[activities addObject:[[NSString alloc]initWithFormat:#"%#: %# minutes", style, self.nameField.text]];
secondViewController.activities = activities;
*/
// New code
MyActivity *activity=[[MyActivity alloc]init];
activity.description=self.activityField.text;
activity.duration=[self.nameField.text intValue];
activity.intensity=(styleSeg.selectedSegmentIndex == 0) ? 3:6;
[self.activities addObject:activity];
secondViewController.activities = activities;
}
}
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
IBOutlet UIView *secondView;
IBOutlet UILabel *nameLabel;
}
#property IBOutlet UITableView *activityTableView;
#property NSMutableArray* activities;
//#property NSMutableArray* activityName;
#property UIView *secondView;
#property UILabel *nameLabel;
#property (weak, nonatomic) IBOutlet UILabel *nameLabel2;
#property id infoRequest;
-(IBAction)goBack:(id)sender;
#end
SecondViewController.m
#import "SecondViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize secondView;
#synthesize nameLabel;
#synthesize nameLabel2;
#synthesize activities;
#synthesize infoRequest;
#synthesize activityTableView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.nameLabel.text = [self.infoRequest description];
self.nameLabel2.text = [self.infoRequest description];
// activities = [[NSArray alloc] init];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)goBack:(id)sender
{
UINavigationController* parent = (UINavigationController*)[self parentViewController];
[parent popViewControllerAnimated:YES];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Number of rows is the number of time zones in the region for the specified section.
return [activities count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellReuseIdentifier = #"CellReuseIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellReuseIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellReuseIdentifier];
}
NSString* s = [activities objectAtIndex:indexPath.row];
cell.textLabel.text = s;
return cell;
}
Your array seems to hold arbitrary strings, not integers represented as strings (the intValue of "10" is 10, but the intValue of "Moderate intensity for: 10 minutes" is 0). Also you are adding multiple elements for each instance of an activity - the activity description and the activity duration.
I would create another object class to encapsulate the activity -
MyActivity.h
#interface MyActivity : NSObject
#property (copy,nonatomic) NSString *description;
#property int duration;
#property int intensity;
#end
Create a UIButton and set it's touch up inside event to doAddToArray. This will add an entry to the array for each new activate. Allocate a new MyActivity and set the appropriate properties before adding it to the array -
In ViewController.m
-(IBAction)doAddToArray:(id)sender {
MyActivity *activity=[[MyActivity alloc]init];
activity.description=self.activityField.text;
activity.duration=[self.nameField.text intValue];
activity.intensity=(styleSeg.selectedSegmentIndex == 0) ? 3:6;
[self.activities addObject:activity];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"SecondViewControllerSegue"]) {
SecondViewController *secondViewController
= [segue destinationViewController];
secondViewController.activities = activities;
}
Then in SecondViewController.h
#import <UIKit/UIKit.h>
#interface SecondViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
IBOutlet UIView *secondView;
IBOutlet UILabel *nameLabel;
}
#property IBOutlet UITableView *activityTableView;
#property UIView *secondView;
#property UILabel *nameLabel;
#property (weak, nonatomic) IBOutlet UILabel *nameLabel2;
#property (weak, nonatomic) NSArray *activities; // This is used to provide content to the UITableView
#property id infoRequest;
-(IBAction)goBack:(id)sender;
#end
For brevity I won't include the full SecondViewController.m, but you have a number of places where you use activities that should be self.activities
Then to total the array (wherever you need to)-
int total=0;
for (MyActivity *activity in self.activities)
{
total+=activity.duration*activity.intensity;
}

UIPickerView stops NSTimer

I've been working on a small app that contains only two elements, a UILabel and a UIPickerView.
The UILabel is updated by an NSTimer to count down from 60 to 0.
The UIPickerView only contains an array of data, don't interact directly with either UILabel with NSTimer.
My problem is that when I play with the UIPickerView and I scroll up or down, the counter "animation" stops, continues to make its action until you select an option from the UIPickerView.
I could not fix this, I do not know if it's a bug with the iPhone SDK or is there any property as becomeFirstResponder that can help me.
I'm using iOS SDK 6.1.
This is my code:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UIPickerViewDataSource,UIPickerViewDelegate>{
IBOutlet UIPickerView *uno;
NSMutableArray *numeros;
NSTimer *timer;
IBOutlet UILabel *contador;
int num;
}
#property (nonatomic, retain) IBOutlet UIPickerView *uno;
#property (nonatomic, retain) NSMutableArray *numeros;
#property (nonatomic, retain) IBOutlet UILabel *contador;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize uno, numeros, contador;
- (void)viewDidLoad
{
[super viewDidLoad];
numeros = [[NSMutableArray alloc] init];
[numeros addObject:#"0"];
[numeros addObject:#"1"];
[numeros addObject:#"2"];
[numeros addObject:#"3"];
[numeros addObject:#"4"];
[numeros addObject:#"5"];
[numeros addObject:#"6"];
[numeros addObject:#"7"];
[numeros addObject:#"8"];
[numeros addObject:#"9"];
uno.delegate = self;
uno.dataSource = self;
num = 60;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component {
return [numeros count];
}
- (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [numeros objectAtIndex:row];
}
- (void)pickerView:(UIPickerView *)thePickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSLog(#"Hi");
}
- (void)updateCounter:(NSTimer *)theTimer {
num = num - 1;
[contador setText:[NSString stringWithFormat:#"%d",num]];
}
#end
The app looks like this: http://imgur.com/ljB93tN
add NSRunLoop after
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(updateCounter:) userInfo:nil repeats:YES];
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:timer forMode: NSDefaultRunLoopMode];

AddRecord TableView controller -->MasterTableView Controller --> second (filter) TableView Controller --> DetailView Controller

I'm new to iOS programing (and programming in general). I'm trying to do an iPhone App based on the Birdsighting example provided by Apple (http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/SecondiOSAppTutorial/Introduction/Introduction.html). The difference is that I will create Body Building's workouts (instead of Birdsightings) in an AddWorkout TableView Controller, pass the workout to the Master TableView Controller and from there being able, by selecting a workout's cell, to display a second TableView Controller similar to the Master's one, that shows events of that workout sorted by muscle bands; then, selecting a muscle band cell, pushing a DetailView Controller with all relative parameters of that muscle band's workout (exercise type, weight, series number....). All this is embedded in a navigation controller.
The problem is that I can't pass a new record on the second TableView Controller (MuscleBandViewController) and therefore I can't neither push it to the detailViewController. Any suggestion? I'm stuck for a week 'til now (sorry for my bad English: I'm Italian).
Here is my DataController.h code:
#import <Foundation/Foundation.h>
#class Workouts;
#interface IFitDataController : NSObject
#property (nonatomic, copy)NSMutableArray *masterWorkoutsList;
#property (nonatomic, copy)NSMutableArray *masterMuscleBandList;
- (NSUInteger)countOfList;
- (NSUInteger)countOfMuscleBandList;
- (Workouts *)objectInListAtIndex:(NSUInteger)theIndex;
- (Workouts *)objectInMasterMuscleBandListAtIndex:(NSUInteger)index;
- (void)addWorkoutsWithWorkouts:(Workouts *)thisWorkout;
#end
Here DataController.m:
#import "IFitDataController.h"
#import "Workouts.h"
#interface IFitDataController ()
- (void)initializeDefaultDataList;
#end
#interface IFitDataController ()
- (void)initializeMuscleBandDataList;
#end
#implementation IFitDataController
- (void)initializeDefaultDataList {
NSMutableArray *workoutsList = [[NSMutableArray alloc] init];
self.masterWorkoutsList = workoutsList;
Workouts *thisWorkout;
NSDate *today = [NSDate date];
thisWorkout = [[Workouts alloc] initWithName:#"Pectorals" exercise:#"Pectoral Machine" series:#"3" nActionsInSerie:#"10" measure:#"Kg" weight:#"25" date:today comment:#"Add your comment"];
[self addWorkoutsWithWorkouts:thisWorkout];
}
- (void)setMasterWorkoutsList:(NSMutableArray *)newList {
if (_masterWorkoutsList != newList) {
_masterWorkoutsList = [newList mutableCopy];
}
}
- (void)initializeMuscleBandDataList {
NSMutableArray *muscleBandList = [[NSMutableArray alloc]init];
self.masterMuscleBandList = muscleBandList;
Workouts *thisWorkout;
NSDate *today = [NSDate date];
thisWorkout = [[Workouts alloc] initWithName:#"Pectorals" exercise:#"Pectoral Machine" series:#"3" nActionsInSerie:#"10" measure:#"Kg" weight:#"25" date:today comment:#"Add your comment"];
[self addWorkoutsWithWorkouts:thisWorkout];
}
- (void)setMasterMuscleBandList:(NSMutableArray *)newMuscleBandList {
if ((_masterMuscleBandList != newMuscleBandList)) {
_masterMuscleBandList = [newMuscleBandList mutableCopy];
}
}
- (id)init {
if (self = [super init]) {
[self initializeDefaultDataList];
[self initializeMuscleBandDataList];
return self;
}
return nil;
}
- (NSUInteger)countOfList {
return [self.masterWorkoutsList count];
}
- (NSUInteger)countOfMuscleBandList {
return [self.masterMuscleBandList count];
}
- (Workouts *)objectInListAtIndex:(NSUInteger)theIndex {
return [self.masterWorkoutsList objectAtIndex:theIndex];
}
- (Workouts *)objectInMasterMuscleBandListAtIndex:(NSUInteger)index {
return [self.masterMuscleBandList objectAtIndex:index];
}
- (void)addWorkoutsWithWorkouts:(Workouts *)thisWorkout {
[self.masterWorkoutsList addObject:thisWorkout];
[self.masterMuscleBandList addObject:thisWorkout];
}
#end
Here my AddWorkoutViewController.h:
#import <UIKit/UIKit.h>
#define muscleBandComponent 0
#define exercisesComponent 1
#class Workouts;
#interface AddWorkoutViewController : UITableViewController <UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource> {
IBOutlet UIPickerView *exercisePicker;
IBOutlet UITextView *commentInserted;
NSArray *_exercisesForPicker;
NSArray *_muscleBandForPicker;
NSDictionary *totalExercises;
}
#property (weak, nonatomic) IBOutlet UITextField *muscleBandName;
#property (weak, nonatomic) IBOutlet UITextField *exerciseName;
#property (weak, nonatomic) IBOutlet UILabel *nSeries;
#property (weak, nonatomic) IBOutlet UILabel *measureType;
#property (weak, nonatomic) IBOutlet UILabel *nActionsInSerie;
#property (weak, nonatomic) IBOutlet UILabel *weightPerformed;
#property (strong, nonatomic) IBOutlet UITextView *commentInserted;
#property (retain, nonatomic) IBOutlet UIPickerView *exercisePicker;
#property (retain, nonatomic) NSArray *muscleBandForPicker;
#property (retain, nonatomic) NSDictionary *totalExercises;
#property (retain, nonatomic) NSArray *exercisesForPicker;
- (IBAction)nSeriesStepper:(id)sender;
- (IBAction)nActionsSerieStepper:(id)sender;
- (IBAction)weightStepper:(id)sender;
- (void) closeKeyboard;
#property (strong, nonatomic) Workouts *workout;
#end
Here my AddWorkoutViewController.m:
#import "AddWorkoutViewController.h"
#import "Workouts.h"
#import "IFitDataController.h"
#interface AddWorkoutViewController ()
#end
#implementation AddWorkoutViewController
#synthesize exercisePicker;
#synthesize totalExercises;
#synthesize exercisesForPicker;
#synthesize muscleBandForPicker;
#synthesize nSeries;
#synthesize nActionsInSerie;
#synthesize weightPerformed;
#synthesize commentInserted;
- (IBAction)nSeriesStepper:(id)sender {
self.nSeries.text = [NSString stringWithFormat:#"%d", [[NSNumber numberWithDouble:[(UIStepper *)sender value]] intValue]];
}
- (IBAction)nActionsSerieStepper:(id)sender {
self.nActionsInSerie.text = [NSString stringWithFormat:#"%d", [[NSNumber numberWithDouble:[(UIStepper *)sender value]] intValue]];
}
- (IBAction)weightStepper:(id)sender {
self.weightPerformed.text = [NSString stringWithFormat:#"%d", [[NSNumber numberWithDouble:[(UIStepper *)sender value]] intValue]];
}
- (IBAction) go:(id)sender
{
[self closeKeyboard];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ReturnInput"]) {
if ([self.exerciseName.text length] || [self.muscleBandName.text length]) {
Workouts *thisWorkout;
NSDate *today = [NSDate date];
thisWorkout = [[Workouts alloc] initWithName:self.muscleBandName.text exercise:self.exerciseName.text series:self.nSeries.text nActionsInSerie:self.nActionsInSerie.text measure:self.measureType.text weight:self.weightPerformed.text date:today comment:self.commentInserted.text];
self.workout = thisWorkout;
}
}
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ((textField == self.exerciseName) || (textField == self.muscleBandName)) {
[textField resignFirstResponder];
}
return YES;
}
- (void) closeKeyboard
{
if([commentInserted isFirstResponder])
{
[commentInserted resignFirstResponder];
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Initialization code
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"muscleBands" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.totalExercises = dictionary;
NSArray *components = [self.totalExercises allKeys];
NSArray *sorted = [components sortedArrayUsingSelector:#selector(compare:)];
self.muscleBandForPicker = sorted;
NSString *selectedMuscleBand = [self.muscleBandForPicker objectAtIndex:0];
NSArray *array = [totalExercises objectForKey:selectedMuscleBand];
self.exercisesForPicker = array;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 2;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if (component == muscleBandComponent)
return [self.muscleBandForPicker count];
return [self.exercisesForPicker count];
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
if (component == muscleBandComponent)
return [self.muscleBandForPicker objectAtIndex:row];
return [self.exercisesForPicker objectAtIndex:row];
}
-(void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
if (component == muscleBandComponent) {
NSString *selectedMuscleBand = [self.muscleBandForPicker objectAtIndex:row];
NSArray *array = [totalExercises objectForKey:selectedMuscleBand];
self.exercisesForPicker = array;
[exercisePicker selectRow:0 inComponent:exercisesComponent animated:YES];
[exercisePicker reloadComponent:exercisesComponent];
self.muscleBandName.text = [muscleBandForPicker objectAtIndex:row];
return;
}
self.exerciseName.text = [exercisesForPicker objectAtIndex:row];
}
#end
Here my MasterViewController.h:
#import <UIKit/UIKit.h>
#class IFitDataController;
#class Workouts;
#interface IFitMasterViewController : UITableViewController
#property (strong, nonatomic) IFitDataController *dataController;
#property (strong, nonatomic) IFitDataController *muscleBandDataController;
#property (strong, nonatomic) Workouts *thisWorkout;
- (IBAction)done:(UIStoryboardSegue *)segue;
- (IBAction)cancel:(UIStoryboardSegue *)segue;
#end
Here MasterViewController.m::
#import "IFitMasterViewController.h"
#import "IFitDetailViewController.h"
#import "IFitDataController.h"
#import "Workouts.h"
#import "AddWorkoutViewController.h"
#import "IFitMuscleBandViewController.h"
#implementation IFitMasterViewController
- (IBAction)done:(UIStoryboardSegue *)segue {
if ([[segue identifier] isEqualToString:#"ReturnInput"]) {
AddWorkoutViewController *addController = [segue sourceViewController];
if (addController.workout) {
[self.dataController addWorkoutsWithWorkouts:addController.workout];
[[self tableView] reloadData];
}
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
- (IBAction)cancel:(UIStoryboardSegue *)segue
{
if ([[segue identifier] isEqualToString:#"CancelInput"]) {
[self dismissViewControllerAnimated:YES completion:NULL];
}
}
- (void)awakeFromNib
{
[super awakeFromNib];
self.dataController = [[IFitDataController alloc]init];
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.dataController countOfList];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"WorkoutCell";
static NSDateFormatter *formatter = nil;
if (formatter == nil) {
formatter = [[NSDateFormatter alloc]init];
[formatter setDateStyle:NSDateFormatterFullStyle];
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Workouts *workoutAtIndex = [self.dataController objectInListAtIndex:indexPath.row];
[[cell textLabel]setText:[formatter stringFromDate:(NSDate *)workoutAtIndex.date]];
[[cell detailTextLabel]setText:workoutAtIndex.comment];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return NO;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowMuscleBandList"]) {
IFitMasterViewController *muscleBandViewController = [segue destinationViewController];
muscleBandViewController.thisWorkout = [self.muscleBandDataController objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}
#end
Here MuscleBandViewController.h:
#import <UIKit/UIKit.h>
#class IFitDataController;
#interface IFitMuscleBandViewController : UITableViewController
#property (strong, nonatomic) Workouts *thisWorkout;
#property (strong, nonatomic) IFitDataController *dataController;
#property (strong, nonatomic) IFitDataController *muscleBandDataController;
#end
Here MuscleBandViewController.m:
#import "IFitMasterViewController.h"
#import "IFitDetailViewController.h"
#import "IFitDataController.h"
#import "Workouts.h"
#import "AddWorkoutViewController.h"
#import "IFitMuscleBandViewController.h"
#class IFitDataController;
#implementation IFitMuscleBandViewController
- (void)awakeFromNib
{
[super awakeFromNib];
self.muscleBandDataController = [[IFitDataController alloc]init];
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.muscleBandDataController countOfMuscleBandList];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"MuscleBandCell";
static NSDateFormatter *formatter = nil;
if (formatter == nil) {
formatter = [[NSDateFormatter alloc]init];
[formatter setDateStyle:NSDateFormatterFullStyle];
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
Workouts *workoutAtIndex = [self.muscleBandDataController objectInMasterMuscleBandListAtIndex:indexPath.row];
[[cell textLabel]setText:workoutAtIndex.muscleBand];
[[cell detailTextLabel]setText:workoutAtIndex.comment];
return cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowWorkoutDetails"]) {
IFitDetailViewController *detailViewController = [segue destinationViewController];
detailViewController.thisWorkout = [self.muscleBandDataController objectInMasterMuscleBandListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
}
#end
Here DetailViewController.h:
#import <UIKit/UIKit.h>
#class Workouts;
#interface IFitDetailViewController : UITableViewController
#property (strong, nonatomic) Workouts *thisWorkout;
#property (weak, nonatomic) IBOutlet UILabel *muscleBandLabel;
#property (weak, nonatomic) IBOutlet UILabel *exerciseLabel;
#property (weak, nonatomic) IBOutlet UILabel *seriesLabel;
#property (weak, nonatomic) IBOutlet UILabel *nActionsInSerieLabel;
#property (weak, nonatomic) IBOutlet UILabel *measureLabel;
#property (weak, nonatomic) IBOutlet UILabel *weightLabel;
#property (weak, nonatomic) IBOutlet UILabel *dateLabel;
#property (weak, nonatomic) IBOutlet UILabel *commentLabel;
#end
and finally my DetailViewController.m:
#import "IFitDetailViewController.h"
#import "Workouts.h"
#interface IFitDetailViewController ()
- (void)configureView;
#end
#implementation IFitDetailViewController
#pragma mark - Managing the detail item
- (void)setWorkout:(Workouts *)newWorkout
{
if (_thisWorkout != newWorkout) {
_thisWorkout = newWorkout;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
Workouts *theWorkout = self.thisWorkout;
static NSDateFormatter *formatter = nil;
if (formatter == nil) {
formatter = [[NSDateFormatter alloc]init];
[formatter setDateStyle:NSDateFormatterMediumStyle];
}
if (theWorkout) {
self.muscleBandLabel.text = theWorkout.muscleBand;
self.exerciseLabel.text = theWorkout.exercise;
self.seriesLabel.text = theWorkout.series;
self.nActionsInSerieLabel.text = theWorkout.nActionsInSerie;
self.measureLabel.text = theWorkout.measure;
self.weightLabel.text = theWorkout.weight;
self.title = [formatter stringFromDate:(NSDate *)theWorkout.date];
self.commentLabel.text = theWorkout.comment;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

Resources