我想在 tableview 中设置多个运行计时器值,以便用户轻松检查剩余时间并停止任何特定计时器。
Multiple Timer Start 和 updated value 完美地显示在 NSLog
中。
用户为特定配方设置 NSTimer
。
现在假设用户在 recipedetail 中为 recipe1 设置了计时器,现在从那个 recipedetail 返回。
然后再次在 recipedetail 中为 recipe2 设置计时器,然后从该 recipedetail 返回。
我想在 UITableView
中显示所有计时器值。并将 tableview 放置在 recipedetail 屏幕上。
所以我的观点是 TimerUpdated 值显示在 NSLog
中但不显示在 tableview 中,因为每个 Recipedetails 屏幕都会生成 UITableView
的新对象所以值不会更新 perfactly
-(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 单元格
这是示例演示,您可以尝试使用单独的项目,
首先创建 NSObject
的 Recipe
类子类,如下所示,
在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文件中
#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
详细 Controller 与您的食谱详细 Controller 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
关于ios - 如何在 Tableview 单元格 iOS 中显示更新的多个 NStimer 值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35715182/