here is my code:
-(void)flash_random_winning_number:(NSInteger)param_which_magic_number
{
NSInteger dd = 9;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:.5
target:self
selector:#selector(ShowLabel22:dd:)
userInfo:Nil
repeats: YES
];
}//flash_random_winning_number
the problem is with selector:#selector(ShowLabel22:dd:) because I am sending a parameter to this method called ShowLabel22:
-(void)ShowLabel:(NSInteger)param_which_magic_number
{
random_magic_number1.hidden = NO;
}
however if I were to remove the parameters from all this code, then there is no error. Therefore it seems as if I have mistake in the way I am using parameters.
The selector you pass to scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: is akin to the name of a function. What you’re trying to do is to pass in the name of a function and the value of its parameters, but that won’t work. The method you name using #selector(...) will be passed exactly one argument: the NSTimer object calling the method.
If you have data you need to make available to ShowLabel it needs to be attached to the timer object or to self or something like that. To attach your number to the timer object you could do this:
- (void) flash_random_winning_number:(NSInteger) param_which_magic_number
{
NSInteger dd = 9;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:.5
target:self
selector:#selector(ShowLabel:)
userInfo:#(dd)
repeats:YES];
}
- (void) ShowLabel:(NSTimer *)timer
{
NSInteger dd = [[timer userInfo] integerValue];
/* do stuff with dd */
}
(Since you’re new to Objective-C I want to mention the conventions that have arisen about method naming. The usual style, which you should always use, is for methods to be named with camelCasedNamesLikeThis. In particular, flash_random_winning_number and ShowLabel are both likely to confuse other Objective-C developers because they don’t “look like” method names. ShowLabel22 is also weird because of the numbers, but since you included that in one place in your question but not another I guess that’s just a typo.)
Look at this SO answer. When you have a selector with arguments you have to use this method:
[self performSelector:#selector(myTest:) withObject:myString];
Related
I have the following method
-(void)changeLevelWithTimeInterval:(NSTimeInterval)timeInterval withLevel:(NSUInteger)level{
[NSTimer scheduledTimerWithTimeInterval:timeInterval
target:self
selector:#selector(changeLevel:)
userInfo:nil
repeats:NO];
}
and I want to call the changeLevel:(NSUInteger)level method with the level argument of the method above.
I have tried to put
[self performSelector:#selector(changeLevel:) withObject:level]
and tried to pass this as an argument but it doesn't work.
performSelector:withObject: takes a pointer object (aka an id) as an argument, so there is no way to pass in an NSUInteger as an argument, as NSUInteger is just a typedeffed unsigned int. One particular workaround is to encapsulate the level in an NSNumber object, and get the intValue of the NSNumber in the changeLevel: method.
It may go as:
NSNumber *levelNumber = [NSNumber numberWithInt:(int)level];
[self performSelector:#selector(changeLevel:) withObject:levelNumber];
And change the signature and implementation of changeLevel: as follows:
-(void)changeLevel:(NSNumber*)levelNumber{
int level = [levelNumber intValue];
//do anything you want with the level..
}
For firing the method after an interval, you can try:
[self performSelector:#selector(changeLevel:) withObject:levelNumber afterDelay:timeInterval];
Instead of scheduling a timer directly.
I ended up using the following method instead of the method above to make everything work correctly.
-(void)changeLevelWithTimeInterval:(NSTimeInterval)timeInterval withLevel:(NSUInteger)level{
NSNumber *levelNumber = [NSNumber numberWithInt:(int)level];
[self performSelector:#selector(changeLevel:) withObject:levelNumber afterDelay:timeInterval];
}
I have an NSTimer which I want to update a label every second. My code is:
- (IBAction)OnClickEmergencyButton:(id)sender
{
emergencyAlertTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(emergencyTimer) userInfo:nil repeats:YES];
[emergencyAlertTimer fire];
}
- (void)emergencyTimer
{
int i = 0;
_emergencyAlertTriggerTimerLabel.text = [NSString stringWithFormat:#"%d", ++i];
}
When I ran it, the label displayed "1" initially and then stopped.
I want the label to continuously count up every second, like "1", "2", "3", ...
There is no issue with your timer. The issue is with the variable declaration inside the emergencyTimer, you declared it as a local variable. So each time when the timer fires the variable will be initialized to 0 again. So declare the variable as static, so that it can preserve the value.
Change the method like:
-(void)emergencyTimer
{
static int timeValue = 0;
_emergencyAlertTriggerTimerLabel.text = [NSString stringWithFormat:#"%d",++timeValue];
}
Why static variable and Why not instance variable ?
I didn't used instance variable, for keeping the variable "Scope" safe. If I put it as an instance variable, it can be accessed by other methods of the same class, if there is no need of that functionality, I think using a static variable will be better.
Issue is with this code
int i=0;
Every time when timer method gets called, the integer i gets initialized and label will be displayed as "1" always.
Make this variable global or static to fix your issue.
Remove int i=0; from your timer action method because it will always have a value of zero. You should be using an instance variable (#property) to store the timerCounter and increment that and use it to populate the label.
At some point in time you need to invalidate the timer. This is particularly important to do before you create a new timer and replace the reference to the old timer. Currently, if you press the button twice, you will then have 2 timers running and your label will increment twice a second...
#property (nonatomic, assign) NSInteger timerCounter;
- (IBAction)OnClickEmergencyButton:(id)sender {
[emergencyAlertTimer invalidate];
emergencyAlertTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(emergencyTimer) userInfo:nil repeats:YES];
[emergencyAlertTimer fire];
}
- (void)emergencyTimer {
_emergencyAlertTriggerTimerLabel.text = [NSString stringWithFormat:#"%d", self.timerCounter];
self.timerCounter++;
}
You should also invalidate the timer when the view is removed from display / deallocated.
Always timer get called emergencyTimer but your value of i won't changed because it's an local variable, scope of i will remain at end of function call. Try this with static variable which remain globally...
-(void)emergencyTimer{
static int i=0; // initialize at first time only..
_emergencyAlertTriggerTimerLabel.text = [NSString stringWithFormat:#"%d",++i];
if ( i == 100)
[ emergencyAlertTimer invalidate] // stop at certain condition
}
Firstly everyone is right you will only display a 0 no matter what you do currently so use an instance variable.
With regards to the only firing once, instead of [NSTimer fire] try this:
emergencyAlertTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(emergencyTimer) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:emergencyAlertTimer forMode:NSRunLoopCommonModes];
I have surfed on a bunch of resources from the internet but still couldn't get any idea of what I'm trying to implement.
I would like to record user preferences by detecting how much time they have stayed in each information pages.
In order to make this question simpler, that says I have a entrance page with 5 different theme pages which represent different information.
I would like to know which page is the page that user most interesting.
What I wish to do is to put a counter in each theme pages and calculate how much time they stay in that page (the counter should be able to pause for reentrance), and then when I press a button on the entrance page, an alert will tell me which page is the page that user spent most of time on it.
I hope this make sense!
Does anyone have any experience on this? I would be most appreciative if anyone can provide some codes and examples for me.
ViewController A:
- (void)viewDidLoad {
[super viewDidLoad];
//create iVar of NSInteger *seconds
seconds = 0;
NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:#selector(increaseTimeCount) userInfo:nil repeats:YES];
[timer fire];
}
- (void)increaseTimeCount {
seconds++;
}
- (void)dealloc {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// you can add to array too , if you want and get average of all values later
[defaults setInteger:seconds forKey: NSStringFromClass(self)];
}
now in Entrance View ..
get the time as
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger *secondsInView = [defaults integerForKey:NSStringFromClass(View1ClassName)];
Firstly I'd like to draw your attention to the Cocoa/CF documentation (which is always a great first port of call). The Apple docs have a section at the top of each reference article called "Companion Guides", which lists guides for the topic being documented (if any exist). For example, with NSTimer, the documentation lists two companion guides:
Timer Programming Topics for Cocoa
Threading Programming Guide
For your situation, the Timer Programming Topics article is likely to be the most useful, whilst threading topics are related but not the most directly related to the class being documented. If you take a look at the Timer Programming Topics article, it's divided into two parts:
Timers
Using Timers
For articles that take this format, there is often an overview of the class and what it's used for, and then some sample code on how to use it, in this case in the "Using Timers" section. There are sections on "Creating and Scheduling a Timer", "Stopping a Timer" and "Memory Management".There are a couple of ways of using a timer. From the article, creating a scheduled, non-repeating timer can be done something like this:
1) scheduled timer & using selector
NSTimer *t = [NSTimer scheduledTimerWithTimeInterval: 2.0
target: self
selector:#selector(onTick:)
userInfo: nil repeats:NO];
if you set repeats to NO, the timer will wait 2 seconds before
running the selector and after that it will stop;
if repeat: YES, the timer will start immediatelly and will repeat
calling the selector every 2 seconds;
to stop the timer you call the timer's -invalidate method: [t
invalidate]; As a side note, instead of using a timer that doesn't
repeat and calls the selector after a specified interval, you could
use a simple statement like this:
[self performSelector:#selector(onTick:) withObject:nil afterDelay:2.0];
this will have the same effect as the sample code above; but if you want to call the selector every nth time, you use the timer with repeats:YES;
2) self-scheduled timer
NSDate *d = [NSDate dateWithTimeIntervalSinceNow: 60.0];
NSTimer *t = [[NSTimer alloc] initWithFireDate: d
interval: 1
target: self
selector:#selector(onTick:)
userInfo:nil repeats:YES];
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:t forMode: NSDefaultRunLoopMode];
[t release];
this will create a timer that will start itself on a custom date
specified by you (in this case, after a minute), and repeats itself
every one second
3) unscheduled timer & using invocation
NSMethodSignature *sgn = [self methodSignatureForSelector:#selector(onTick:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:#selector(onTick:)];
NSTimer *t = [NSTimer timerWithTimeInterval: 1.0
invocation:inv
repeats:YES];
and after that, you start the timer manually whenever you need like this:
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];
And as a note, onTick: method looks like this:
-(void)onTick:(NSTimer *)timer {
//do smth
}
Try this simple method:
- (void)viewDidLoad
{
[super viewDidLoad];
count = 0; // Declare int * count as global variable;
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(timerAction) userInfo:nil repeats:YES];
}
- (void)timerAction
{
[self custom_method:count++]
}
Might I suggest a different route. If you take the time since reference date, when the user enters the page:
NSTimeINterval time = [NSDate timeIntervalSinceReferenceDate]
then do the same when they leave the page and compare them.
timeOnPage = time - time2;
This is much more efficient than firing a timer on another thread unnecessary.
You do not need to use NSTimers for this at all.
Store the date/time when the user starts viewing, and calculate the time difference when they stop viewing using simple time arithmetic.
Exactly As Dave Wood says You should use date and time for starting and ending viewing that screen and calculate the difference and then save it to any integer variable.Using NSTimer will make the performance effect in your app and make the compiler busy while incrementing the count.
I'm trying to start a NSTimer in my UIView class called "ClockView" with a method as selector that manipulates an initial float which was declared in the ViewController "ClockViewController".
My ClockViewController declares int timerIntWhite as an integer (for example 500). My ClockView needs this Value for the - (void)start method which runs a method called - (void)updateWhiteClock every second:
- (void)start {
timerIntWhite = PLEASE HELP ME AT THIS POINT!;
randomTimerWhite = [NSTimer scheduledTimerWithTimeInterval:(1.0/1.0)target:self selector:#selector(updateWhiteClock) userInfo:nil repeats:YES];
}
Is it possible to access the integer of ClockViewController in ClockView?
Try the following:
In your ClockView also declare the variable (property) int timerIntWhite and set this variable from your View Controller after the View gets created, for example, in viewDidLoad.
-(void)viewDidLoad {
[super viewDidLoad];
self.view.timerIntWhite = self.timerIntWhite;
}
After doing this, ClockView can access it's own timerIntWhite variable:
- (void)start {
timerIntWhite = self.timerIntWhite;
randomTimerWhite = [NSTimer scheduledTimerWithTimeInterval:(1.0/1.0)target:self selector:#selector(updateWhiteClock) userInfo:nil repeats:YES];
}
I'm assuming that your ClockViewController class knows that its view IS-A ClockView. This is very important! Otherwise you'll get a warning.
I also want to mention that according to the MVC rules it's a better idea if your ClockViewController class takes care of the NSTimer. Views should be used to display information to the user only.
Hope this helps!
I have a view-based template app and have UILabel & UIButton. For debugging purposes I'm showing and hiding the button whilst changing the UILabel.text.
In C++ I would 'thread root();' to execute the root method but I don't know how to in Objective-c. How to run my 'root' method once the view loads?
-(void) root
{
[bombButton1 setHidden:NO];
int s = 0;
int j = 10;
while ( s < j )
{
[bombButton1 setHidden:YES];
NSString *debugLabelString = [NSString stringWithFormat:#"%d", s];
debugLabel.text=debugLabelString;
s++;
}
Edit:
Right, now I have: (but I get ERROR: Expected method body on the "-(void) rootMethod: NSTimer * timer {" line)
-(void) applicationDidFinishLaunching : (UIApplication *) application {
spawnTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target:self selector:#selector(rootMethod:) userInfo:nil repeats: YES];
}
-(void) rootMethod: NSTimer * spawnTimer {
int s = 0;
int j = 10;
while ( s < j )
{
NSString *debugLabelString = [NSString stringWithFormat:#"%d", s];
debugLabel.text=debugLabelString;
//debugLabel.text=#"debug test complete";
s++;
}
}
Several ways to do this, I think. Here's one:
[self performSelectorInBackground:#selector(root) withObject:nil];
You'd make this call in say, your -(void)viewDidAppear: method.
You may run into issues running code on threads other than the main thread that tries to manipulate the UI.
That sleep(1) is worrisome. You could use a repeating NSTimer instead and eliminate the sleep(1) entirely. Something like:
[NSTimer scheduledTimerWithInterval:2.0 target:self
selector:#selector(root:) userInfo:nil repeats:YES];
For NSTimer, you'd have to change your method, root, to have a signature like
- (void)root:(NSTimer*)theTimer
You need to implement a called viewDidLoad.
- (void) viewDidLoad() {
// your code here
}
I'm sure you have your reasons, but you really shouldn't iteract with UI components in anything other than the UI thread. What you actually need to do is use an NSTimer to call a method on the UI thread multiple times.
What you should be doing is performSelectorOnMainThread when you want to update the UI Thread.
Do your running in the background and update variables that will contain the updated values, then use performSelectorOnMainThread on the View, sending it to a method that will merely update the Textbox with the data in the variables.
You can do anything in a background thread, except update the ui.
Edit: Furthermore I dont recommend using Timers in place of background threads, I have had instances when using Timers, where only so many get created and when I expected a background thread to fire, it never did. The timer actually never fired, even tho it was created.