我想在表格视图中设置多个运行计时器值,以便用户轻松检查剩余的时间并停止任何特定的计时器。

多个计时器启动和更新值完美显示在NSLog中。
用户为特定配方设置NSTimer
现在,假设用户在配方详细信息中为配方1设置了计时器,然后从该配方详细信息中返回。
然后再次在配方细节中为配方2设置计时器,并从该配方细节返回。
我想在UITableView中显示所有计时器值。并将tableview放置在recipedetail屏幕上。

所以我的意思是在NSLog中显示TimerUpdated值,但在表视图中不显示,因为每个Recipedetails屏幕都会生成UITableView的新对象,所以该值不会准确地更新

 -(IBAction)okBtn:(id)sender
    {
       [self countdownTimer];
    }
-(void)countdownTimer {

        [[NSUserDefaults standardUserDefaults]setObject:recipeboxId forKey:[NSString stringWithFormat:@"timer_%@",recipeboxId]];
        [[NSUserDefaults standardUserDefaults]synchronize];
        // set timer

        [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
        (theAppDelegate).timer = [NSTimer scheduledTimerWithTimeInterval:0.6f
                                                 target:self
                                               selector:@selector(updateCounter:)
                                               userInfo:recipeboxId
                                                repeats:YES];
        [(theAppDelegate).timer fire];
    //    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];//Timer run in background

        [self CreateLocalNotification];
    }


    -(void)calculateTimeFromPicker
    {
        NSString *hoursStr = [NSString stringWithFormat:@"%@",[hoursArray objectAtIndex:[self.picker_timer selectedRowInComponent:0]]];
        NSString *minsStr = [NSString stringWithFormat:@"%@",[minsArray objectAtIndex:[self.picker_timer selectedRowInComponent:1]]];
        NSString *secsStr = [NSString stringWithFormat:@"%@",[secsArray objectAtIndex:[self.picker_timer selectedRowInComponent:2]]];

        int hoursInt = [hoursStr intValue];
        int minsInt = [minsStr intValue];
        int secsInt = [secsStr intValue];

        interval = secsInt + (minsInt*60) + (hoursInt*3600);
        secondsLeft=interval;
    }
    - (void)updateCounter:(NSTimer *)theTimer {
        if(secondsLeft > 0 )
        {
            secondsLeft -- ;
            hours = secondsLeft / 3600;
            minutes = (secondsLeft % 3600) / 60;
            seconds = (secondsLeft %3600) % 60;

            [[NSUserDefaults standardUserDefaults]setInteger:secondsLeft forKey:[NSString stringWithFormat:@"secondsLeft_%@",recipeboxId]];
            [[NSUserDefaults standardUserDefaults]synchronize];

            NSLog(@"timer :%@",[NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds]);
            NSString *timer_updated_value=[NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
            [[NSUserDefaults standardUserDefaults]setObject:timer_updated_value forKey:[NSString stringWithFormat:@"updated_timer_%@",[(theAppDelegate).timer userInfo]]];
            [[NSUserDefaults standardUserDefaults]synchronize];
             recipeArr = [[(theAppDelegate).Timer_recipeIdArr reverseObjectEnumerator] allObjects];
            for (int section = 0; section < [recipeArr count]; section++)
                for (int section = 0; section < [recipeArr count]; section++)
                {

                    for (int row = 0; row < (int)[self.timerWindowTbl numberOfRowsInSection:section]; row++)
                    {

                        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];

                        UITableViewCell *cell = [self.timerWindowTbl cellForRowAtIndexPath:indexPath];

                                for(UILabel *lbl in [cell.contentView subviews])
                                {
                                    if([lbl isKindOfClass:[UILabel class]])
                                    {

                                        if(lbl.tag == 1)
                                        {
                                            NSString *timer_desc= [[NSUserDefaults standardUserDefaults]objectForKey:[NSString stringWithFormat:@"timerDescString_%@",recipeArr[indexPath.row]]];
                                            NSString *recipe_title=[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"timerRecipeTitle_%@",recipeArr[indexPath.row]]];
                                            NSString *updated_timer=[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:@"updated_timer_%@",recipeArr[indexPath.row]]];

                                            NSString *desc=[NSString stringWithFormat:@"%@\n'%@\' %@ %@.",recipe_title,timer_desc,NSLocalizedString(@"is done in",nil),updated_timer];
                                             lbl.text=updated_timer;
                                            [lbl setNeedsDisplay];

                                            NSLog(@"*******************************lbl.text:%@",lbl.text);
                                            lbl.numberOfLines=0;
                                            [lbl sizeToFit];
                                            for(UIButton *btn in [cell.contentView subviews])
                                            {
                                                if([btn isKindOfClass:[UIButton class]])
                                                {
                                                    if(btn.tag==2)
                                                    {
                                                        btn.titleLabel.text=[NSString stringWithFormat:@"%@",recipeArr[indexPath.row]];
                                                    }
                                                }
                                            }
                                            break;

                                        }
                                    }

                                }
                         }
                }
        }
        else
        {
            secondsLeft = hours = minutes = seconds = 0;
            [self TimerInvalidate];
            NSLog(@"Time out :");
        }
    }

最佳答案

我认为您需要重新展示您的代码,每次当配方计时器盯着特定配方时,都需要重新加载tableview单元格

这是示例演示,您可以尝试使用单独的项目,
首先创建RecipeNSObject类子类,如下所示,

Recipe .h文件中

#import <Foundation/Foundation.h>
@class Recipe;
@protocol RecipeDelegate <NSObject> //we need to notify which recipe time changing
- (void)timerChangedInRecipe:(Recipe *)recipe;
@end


@interface Recipe : NSObject
@property (nonatomic, assign) NSInteger recipeboxId;
@property (nonatomic, strong) NSString *recipeName;
@property (nonatomic, strong) NSString *countTimer;

@property (nonatomic, assign) NSTimeInterval secondsLeft;
@property (nonatomic, assign) NSTimeInterval interval;

@property (nonatomic, assign) int hours;
@property (nonatomic, assign) int minutes;
@property (nonatomic, assign) int seconds;
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, assign) id<RecipeDelegate>delegate;

- (id)initWithRecipieId:(NSInteger)recipeId recipeName:(NSString *)name;
- (void )currentTimerString;
- (void)startTimer; //use to start the timer
- (void)stopTimer;  //stop the timer


@结束

Recipe.m文件中

#import "Recipe.h"

@implementation Recipe
- (id)init
{
  self = [super init];
  if(self)
  {

  }
  return self;
}

- (id)initWithRecipieId:(NSInteger)recipeId recipeName:(NSString *)name
{
   self = [super init];
   if(self)
   {
      self.recipeboxId = recipeId;
      self.recipeName =  name;
   }
   return self;
}

- (void)currentTimerString //this is similar to your method updateCounter:
{
   self.secondsLeft -- ;
   if(self.secondsLeft > 0 )
   {
     _hours = (int)self.secondsLeft / 3600;
     _minutes = ((int)self.secondsLeft % 3600) / 60;
     _seconds = ((int)self.secondsLeft %3600) % 60;
     self.countTimer = [NSString stringWithFormat:@"%02d:%02d:%02d", self.hours, self.minutes, self.seconds];
      if([self.delegate respondsToSelector:@selector(timerChangedInRecipe:)])
         [self.delegate timerChangedInRecipe:self]; //notifying the tableview to reload the particular cell
  }
  else
  {
     _hours = _minutes = _seconds = 0;
     [self stopTimer]; //timer finished stop the timer
  }
}

- (void)startTimer
 {
    if(_timer == nil)
      _timer =  [NSTimer scheduledTimerWithTimeInterval:0.6f target:self selector:@selector(currentTimerString) userInfo:nil repeats:YES];
   else
       [_timer fire];
 }

 - (void)stopTimer
 {
    if(_timer)
      [self.timer invalidate];
    self.timer = nil;
 }
 @end


我们创建了配方对象,它将处理计时器和通知到tableview的信息,启动计时器和停止计时器,如果您愿意,您可以添加一些其他功能.. :)

ViewController.h file

 #import <UIKit/UIKit.h>
 #import "Recipe.h" //import the recipe class
 @interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate,RecipeDelegate>
 @property (weak, nonatomic) IBOutlet UITableView *timerWindowTbl;
 @property (nonatomic, strong) NSMutableArray *recipeArr; //array to hold the recipes
 @end


ViewController.m文件中

#import "ViewController.h"
#import "RecipeDetailViewController.h"

@interface ViewController ()

@end

@implementation ViewController

 - (void)viewDidLoad
 {
   [super viewDidLoad];
   // Do any additional setup after loading the view, typically from a nib.
   _recipeArr = [[NSMutableArray alloc] init];
   [self populateRecipe]; //i am simply creating the recipes hear for testing
 }

 - (void)viewWillAppear:(BOOL)animated
 {
   [super viewWillAppear:animated];
 }

 - (void)populateRecipe
 {
    for(NSInteger k = 0 ; k < 10 ; k++)
    {
      Recipe *recipe = [[Recipe alloc] initWithRecipieId:k recipe eName:[NSString stringWithFormat:@"recipe_%ld",(long)k]];

     [self.recipeArr addObject:recipe];
   }
}

 - (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
 }

 //just configure your tableview
 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 {
    return 1;
 }


 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
  {
    return self.recipeArr.count;
 }

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"RECIPEE_CELL"];
   if(cell == nil)
   {
      cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"RECIPEE_CELL"];
   }
   Recipe *recipe = self.recipeArr[indexPath.row];
   recipe.delegate = self;
   cell.textLabel.text = recipe.recipeName;
   cell.detailTextLabel.text = recipe.countTimer;
   return cell;
 }

 //hear go to recipe detail controller and set timer
 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 {
    Recipe *selRecipe = self.recipeArr[indexPath.row];
    RecipeDetailViewController *recipeDetailController = [[RecipeDetailViewController alloc] initWithNibName:@"RecipeDetailViewController" bundle:nil];
   recipeDetailController.selectedRecipe = selRecipe;
   [self.navigationController pushViewController:recipeDetailController animated:YES];
 }

 //this is the delegate method from recipe class
 //this method is responsible for reloading the particular cell
 - (void)timerChangedInRecipe:(Recipe *)recipe
 {
   NSInteger index = recipe.recipeboxId;
   NSIndexPath *rowPath = [NSIndexPath indexPathForRow:index inSection:0];
   [self.timerWindowTbl reloadRowsAtIndexPaths:@[rowPath] withRowAnimation:UITableViewRowAnimationNone];
 }
 @end


并且详细控制器与您的配方详细控制器RecipeDetailViewController.h文件相同

#import <UIKit/UIKit.h>
#import "Recipe.h"

@interface RecipeDetailViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIDatePicker *timePicker;
@property (weak, nonatomic) IBOutlet UIButton *okButton;
@property (weak, nonatomic) IBOutlet UILabel *timerLabel;
@property (nonatomic, strong) Recipe *selectedRecipe;
- (IBAction)okBtn:(id)sender;
@end


RecipeDetailViewController .m文件中,

 #import "RecipeDetailViewController.h"

 @interface RecipeDetailViewController ()

 @end

 @implementation RecipeDetailViewController

 - (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    [_timePicker addTarget:self action:@selector(timerChanged:) forControlEvents:UIControlEventValueChanged]; //i am setting a sample picker
  }

  - (void)didReceiveMemoryWarning {
   [super didReceiveMemoryWarning];
   // Dispose of any resources that can be recreated.
 }

 - (void)timerChanged:(UIDatePicker *)datePickerView
 {
    NSTimeInterval duration = datePickerView.countDownDuration;
    int hours = (int)(duration/3600.0f);
    int minutes = ((int)duration - (hours * 3600))/60;
    int seconds = minutes/60;
    _selectedRecipe.interval    = seconds + (minutes*60) + (hours*3600);
    _selectedRecipe.secondsLeft =_selectedRecipe.interval;
    _timerLabel.text = [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
   _selectedRecipe.interval = duration;
 }

 - (IBAction)okBtn:(id)sender //hear start the timer particular recipe
 {
   [_selectedRecipe startTimer];
 }
 @end


在源代码中编辑您是共享的
我认为单元格类型中的问题,如果您希望您可以将tableview单元格子类化并将计时器标签放在所需的位置,

因此在您的代码中,ViewController.m文件替换以下方法

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"RECIPEE_CELL"];
    if(cell == nil)
    {
       cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"RECIPEE_CELL"];
    }
    Recipe *recipe = self.recipeArr[indexPath.row];
    recipe.delegate = self;
    cell.textLabel.text = recipe.recipeName;
    cell.detailTextLabel.text = recipe.countTimer;
    NSLog(@"timer in cell :%@",cell.detailTextLabel.text);
    return cell;
 }


然后在RecipeDetailViewController.m文件中替换,

 //no need to wait for value change
- (IBAction)okBtn:(id)sender //hear start the timer particular recipe
 {
    NSTimeInterval duration = _timePicker.countDownDuration;
   _selectedRecipe.interval = duration;
   [_selectedRecipe startTimer];
 }


并在属性检查器中将timePicker模式更改为Count Down Timer

您可以下载编辑后的code hear

10-05 22:57
查看更多