iphone NStimer start in 2 seconds - iphone

I am trying to have a block of code run 2 seconds after I 'start' it.
I think the NSTimer can do this but can't figure it out.

NSTimer can be used, but another option is to use performSelector:withObject:afterDelay: It's basically like a method call (message send) that happens later.
This example will send a doStuff: message after a delay:
[self performSelector:#selector(doStuff:) withObject:self afterDelay:2];
which causes this method to get invoked 2.0 seconds later:
-(void)doStuff:(id)sender
{
/// do something
}

The following will do what you need:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval: 2
target:self
selector:#selector(handleTimer:)
userInfo:nil
repeats:NO];
Then the delegate function:
-(void)handleTimer: (NSTimer *) timer
{
//code
}

You can also use some handy code :
NSObject+PerformBlock.h
#interface NSObject (PerformBlock)
- (void)performBlock:(void(^)(void))block waitUntilDone:(BOOL)wait;
- (void)performBlock:(void(^)(void))block afterDelay:(NSTimeInterval)delay;
- (void)performBlock:(void(^)(void))block repeatCount:(NSUInteger)repeatCount timeInteval:(NSTimeInterval)timeInterval;
#end
NSObject+PerformBlock.m
#interface NSObject (PerformBlockHidden)
- (void)performBlock:(void(^)(void))block;
#end
#implementation NSObject (PerformBlock)
- (void)performBlock:(void(^)(void))block {
block();
}
- (void)performBlock:(void(^)(void))block waitUntilDone:(BOOL)wait {
[self performSelector:#selector(performBlock:) onThread:nil withObject:[[block copy] autorelease] waitUntilDone:wait];
}
- (void)performBlock:(void(^)(void))block afterDelay:(NSTimeInterval)delay {
[self performSelector:#selector(performBlock:) withObject:[[block copy] autorelease] afterDelay:delay];
}
- (void)performBlock:(void(^)(void))block repeatCount:(NSUInteger)repeatCount timeInteval:(NSTimeInterval)timeInterval {
for (NSInteger repetition = 0; repetition < repeatCount; repetition++)
[self performBlock:block afterDelay:(repetition*timeInterval)];
}
#end
Then just import NSObject+PerformBlock.h and call :
[myObject performBlock:^{
// Code you want to perform after 2secs
} afterDelay:2];

You should be able to set the NSTimeInterval to 2.0 seconds and it should fire after that amount of time. What are you seeing? What is the code you are using to invoke the timer?

Related

Change NSTime with respect to the value of UISlider

There are lots of questions and answers about how to change the UISlider value with NsTimer but i need to create the reverse condition i need to change the NSTimer interval per UISlider value change, and want the slider value work in reverse manner. so can anyone help to achieve this?
Thanks for your approaches and time :)
you can set Timer set again interval value at the IBAction of UISlier Method like:-
.h class:-
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
{
IBOutlet UILabel *lblTimer;
IBOutlet UISlider *timeSlider;
}
#property(nonatomic,strong)NSTimer *timer;
.m class:-
- (void)viewDidLoad
{
[super viewDidLoad];
_timer=[[NSTimer alloc]init];
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateLable) userInfo:nil repeats:YES];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
int i=0;
-(IBAction)changeSlider:(UISlider*)sender
{
NSLog(#"%d",(int)sender.value);
[_timer invalidate];
_timer=[[NSTimer alloc]init];
_timer=nil;
_timer = [NSTimer scheduledTimerWithTimeInterval:(int)sender.value target:self selector:#selector(updateLable) userInfo:nil repeats:YES];
// i=0;
//text_field .text= [[NSString alloc] initWithFormat:#" Value %d ", (int)slider.value];
}
-(void)updateLable
{
[lblTimer setText:[NSString stringWithFormat:#"%d",i]];
i++;
}
OUTPUT OF CODE

no known class method for selector 'scheduledTimerWithTimeInterval with timer

I have tried to figure out this, by reading other threads here - but I have not been able to work out anything so far.
If it's be just being a novice that doesn't understand the connections I need to make or if I doesn't have any relevance - I don't know.
I am making an iPhone app with 2 timers in it.
I am working on getting the source code for the timer to work.
I use a flip side application template from xcode, as I want to use the flip side for settings later on (where you can customize timers
In my MainViewController.h:
#import "FlipsideViewController.h"
#import "UIKit/UIKit.h"
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate, UIPopoverControllerDelegate> {
IBOutlet UILabel *timerP1;
IBOutlet UILabel *timerP2;
NSTimer *myTimerP1;
NSTimer *myTimerP2;
}
- (IBAction)startP1;
- (IBAction)stopP1;
- (IBAction)resetP1;
- (void)showActivityP1;
- (IBAction)startP2;
- (IBAction)stopP2;
- (IBAction)resetP2;
- (void)showActivityP2;
#property (strong, nonatomic) UIPopoverController *flipsidePopoverController;
#end
In my MainViewController.m:
#interface MainViewController ()
#end
#implementation MainViewController
- (IBAction)startP1{
myTimerP1 = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(showActivityP1) userinfo:nil repeats:YES];
}
- (IBAction)stopP1{
[myTimerP1 invalidate];
}
- (IBAction)resetP1{
timerP1.text = #"60";
}
- (void)showActivityP1;{
int currentTimeP1 = [timerP1.text intValue];
int newTimeP1 = currentTimeP1 - 1;
timerP1.text = [NSString stringWithFormat:#"%d", newTimeP1];
}
- (IBAction)startP2{
}
- (IBAction)stopP2{
}
- (IBAction)resetP2{
}
- (void)showActivityP2{
}
I get the error "No known class method for selector 'scheduledTimerWithTimeInterval:target:selector:userinfo:repeats:'
What am I doing wrong here?
What am I doing wrong here?
Well, frankly what you're doing wrong is not using autocompletion.
It's a small typo, nothing to worry about.
userinfo should be userInfo (note the capital I)
So the complete call becomes:
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(showActivityP1)
userInfo:nil
repeats:YES];
Oh and by the way - (void)showActivityP1;{...} will cause you troubles as well, just drop the ;

Why isn't there performSelectorOnMainThread: in NSObject Protocol?

Recently I'm working on app. project for iPhone(iOS).
I wonder why there isn't performSelectorOnMainThread: in NSObject Protocol.
I need to call to delegate's methods on main thread 'cause they have to handle UI components.
Here's sample I wrote:
#protocol MyOperationDelegate;
#interface MyOperation : NSOperation {
id <MyOperationDelegate> delegate;
}
#property (nonatomic, assign) id <MyOperationDelegate> delegate;
#end
#protocol MyOperationDelegate <NSObject>
#optional
- (void) didFinishHandleWithResult:(NSDictionary *)result;
#end
#implementation MyOperation
#synthesize delegate;
- (void) main {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSDictionary *aDict = [[MySingleton sharedObject] fetchSomethingMeaningful];
//do something and call delegate
if ([delegate respondsToSelector:#selector(didFinishHandleWithResult:)]) {
[delegate performSelector:#selector(didFinishHandleWithResult:) withObject:
}
[pool release];
}
#end
#interface MyViewCon : UIViewController <MyOperationDelegate> {
NSOperationQueue *queue;
}
#end
#implementation MyViewCon
- (void) viewDidLoad {
MyOperation *op = [[MyOperation alloc] init];
op.delegate = self;
[queue addOperation:op];
[op release];
}
- (void) reloadUserInterface:(NSDictionary *)dict {
// Do reload data on User Interfaces.
}
- (void) didFinishHandleWithResult:(NSDictionary *)myDict {
// Couldn't execute method that's handling UI, maybe could but very slow...
// So it must run on main thread.
[self performSelectorOnMainThread:#selector(reloadUserInterface:) withObject:myDict];
}
#end
Can I run didFinishHandleWithResult: delegate method on main thread in MyOperation class?
Since here I am implementing UI handling method every time I call MyOperation instance.
Any suggestion will be helpful for me.
Let's try:
dispatch_async(dispatch_get_main_queue(), ^{
//your main thread code here
});
NSObject does have a method performSelectorOnMainThread:withObject:waitUntilDone. You can use that.
Yes you can make use of the method like this
[delegate performSelectorOnMainThread:#selector(reloadUserInterface:) withObject:myDict waitUntilDone:YES];

Problem with NSTimer

Edit2: Why only progress got updated in "doSomething" method but not point0?
Edit: with the code I have. I know I must overlook something, but I just could not find it.
I am writing an iphone app which uses NSTimer to do some tasks. In the program, I could not get the updated value of the variable updated inside NSTimer loop. Here is my code.
Interface File
import
#interface TestNSTimerViewController : UIViewController {
IBOutlet UIProgressView *progress;
IBOutlet UIButton *button;
IBOutlet UILabel *lable1;
IBOutlet UILabel *lable2;
NSTimer *timer;
float point0;
}
#property (nonatomic, retain) UIProgressView *progress;
#property (nonatomic, retain) UIButton *button;
#property (nonatomic, retain) NSTimer *timer;
#property (nonatomic, retain) UILabel *lable1;
#property (nonatomic, retain) UILabel *lable2;
- (IBAction)buttonClicked:(id)sender;
#end
Implementation file
#import "TestNSTimerViewController.h"
#implementation TestNSTimerViewController
#synthesize progress;
#synthesize button;
#synthesize lable1;
#synthesize lable2;
#synthesize timer;
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)buttonClicked:(id)sender {
point0 = 1.0f;
lable1.text = [NSString stringWithFormat:#"%3.1f",point0];
timer = [NSTimer scheduledTimerWithTimeInterval:0.05
target:self selector:#selector(doSomething) userInfo:nil repeats:YES];
lable2.text = [NSString stringWithFormat:#"%3.1f",point0];
}
- (void)doSomething {
progress.progress = progress.progress+0.1;
point0 = 2.0f;
if (progress.progress == 1.0) {
[timer invalidate];
}
}
- (void)dealloc {
[button release];
[progress release];
[lable1 release];
[lable2 release];
[timer release];
[super dealloc];
}
#end
After the NSTimer loop, I checked the value of point0. It did not change the value to 2.3. What's wrong with the code?
Thank you,
From the Reference document
Once scheduled on a run loop, the timer fires at the specified interval until it is invalidated. A non-repeating timer invalidates itself immediately after it fires. However, for a repeating timer, you must invalidate the timer object yourself by calling its invalidate method. Calling this method requests the removal of the timer from the current run loop; as a result, you should always call the invalidate method from the same thread on which the timer was installed. Invalidating the timer immediately disables it so that it no longer affects the run loop. The run loop then removes and releases the timer, either just before the invalidate method returns or at some later point. Once invalidated, timer objects cannot be reused.
The timer you use is a Repeating timer, so you should not invalidate it at all. Or use the following Line, because the timer needs to fired each time the button is clicked. I have set the repeat parameter to NO.
timer = [NSTimer scheduledTimerWithTimeInterval:0.05
target:self selector:#selector(doSomething) userInfo:nil repeats:NO];
- (void)buttonClicked:(id)sender {
point0 = 1.0f;
lable1.text = [NSString stringWithFormat:#"%3.1f",point0];
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.05
target:self selector:#selector(doSomething) userInfo:nil repeats:NO];
lable2.text = [NSString stringWithFormat:#"%3.1f",point0];
}
Then in doSometing function:
- (void)doSomething {
progress.progress = progress.progress+0.1;
point0 = 2.0f;
if (progress.progress < 1.0) {
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.05
target:self selector:#selector(doSomething) userInfo:nil repeats:NO];
}
}
I think you should reset the progress variable at some point.
I found the answer. label2.text line is executed before NSTimer finishes the run loop. I need to rewrite my code such that it waits until NSTimer finishes the run loop.

Reduce Core-Graphics memory consumption on iphone

I am writing a program which redraws a graph every so often. Unfortunately it seems that for some reason core graphics does not seem to release the previous graphic so I run into memory problems fast. How can I force it to release memory at the end of each draw?
Not that this is not a memory leak as the memory does get released when I leave close that view. I have tried moving the NSTimer to several places in the code to no avail.
Here is the code below with the files going from most important to (potentially) irrelevant.
First is the core file+header which draws the graphic (in this case a sine wave) every so often.
GraphicsView.h
#import <UIKit/UIKit.h>
#import "Model.h"
#interface GraphicsView : UIView
{
Model * model;
}
#end
GraphicsView.m
#import "GraphicsView.h"
#implementation GraphicsView
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
model=[Model sharedModel];
[NSTimer scheduledTimerWithTimeInterval:.010 target:self selector:#selector(setNeedsDisplay) userInfo:nil repeats:YES];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
int now=[model n];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height));
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextMoveToPoint(context, 0.0, 0.0);
double xc_old=0;
double yc_old=100;
for (int i=0;i<now;i++)
{
double xc=(double)i/(double)now*200;
double yc=100-100*sin((double)i/6);
CGContextMoveToPoint(context, xc_old, yc_old);
CGContextAddLineToPoint(context, xc, yc);
CGContextStrokePath(context);
xc_old=xc;
yc_old=yc;
}
}
- (void)dealloc {
[super dealloc];
}
#end
The view controller header:
#import <UIKit/UIKit.h>
#import "GraphicsView.h"
#interface SbarLeakAppDelegate : NSObject <UIApplicationDelegate>
{
UIWindow *window;
Model *model;
GraphicsView * gv;
NSTimer * timer;
}
#end
The view controller itself.
#import "SbarLeakAppDelegate.h"
#implementation SbarLeakAppDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
model=[Model sharedModel];
CGRect appRect;
CGRect frame = CGRectInset(appRect, 0.0f, 0.0f);
appRect.origin=CGPointMake(0.0, 40.0);
appRect.size = CGSizeMake(200.0f, 200.0f);
frame = CGRectInset(appRect, 0.0f, 0.0f);
gv=[[GraphicsView alloc] initWithFrame:appRect];
[gv setFrame:frame];
[window addSubview:gv];
[gv release];
[window makeKeyAndVisible];
}
-(void) viewDidAppear:(id)sender
{
//timer=[NSTimer scheduledTimerWithTimeInterval:.250 target:gv selector:#selector(setNeedsDisplay) userInfo:nil repeats:YES];
}
- (void)dealloc
{
[window release];
[super dealloc];
}
#end
This code is only included for completeness but (should not) affect the question.
The data source header file (just a simple integer)
#import <UIKit/UIKit.h>
#interface Model : NSObject
{
int n;
}
#property int n;
+(Model *) sharedModel;
-(void) inc;
#end
The data source, Model.m:
#import "Model.h"
#implementation Model
static Model * sharedModel = nil;
+ (Model *) sharedModel
{
if (sharedModel == nil)
sharedModel = [[self alloc] init];
return sharedModel;
}
#synthesize n;
-(id) init
{
self=[super init];
[NSTimer scheduledTimerWithTimeInterval:.05 target:self selector:#selector(inc) userInfo:nil repeats:YES];
return self;
}
-(void) inc
{
n++;
}
#end
The selector you use for your timer does not have the correct signature.
From the Apple docs:
The selector must have the following signature:
- (void)timerFireMethod:(NSTimer*)theTimer
You should use your own method for the timer and call setNeedsDisplay from there. As Robert said, you should turn down the frequency a bit, but I don't think either of these issues will solve your problem.
Did you try: self.clearsContextBeforeDrawing = YES; in the drawRect method ?
According to the NSTimer documentation, the max time resolution is 50-100ms... it looks like you're trying for 1ms... according to spec a timer that asks for finer resolution than that shouldn't cause memory issues, it just shouldn't fire as often as needed. I suspect that's part of your problem, though.
NSTimer Class Reference
Because of the various input sources a
typical run loop manages, the
effective resolution of the time
interval for a timer is limited to on
the order of 50-100 milliseconds.
+ (Model *) sharedModel
{
if (sharedModel == nil)
sharedModel = [[self alloc] init];
return sharedModel;
}
in this snippet, autorelease is missing. This also leads to a leak i think.
try with
sharedModel = [[[self alloc] init] autorelease];