Show NSTimeInterval continously - objective-c

new to the iOS SDK and Objective-C and just have a quick question regarding the NSTimeInterval.
I have a really simple game, and I want to show for how long the game have been played (so that I can save away a best time).
Now, of course if I set the label's text with something like this:
NSTimeInterval elapsedTime = [startDate timeIntervalSinceNow];
theLabel.text = [NSString stringWithFormat:#"%.2f", -elapsedTime];
The text of the label will be how long time it will have passed since the game started, which is 0 seconds.
In what way can I have the elapsedTime object "running in the background" so that the player can se for how long he/she have played at all times?

Have a look as the NSTimer class to schedule a timer for a preset time and update the label in the callback.
-(void)viewDidLoad {
[super viewDidLoad];
// Add timer at 60 frames a second
timer = [NSTimer scheduledTimerWithInterval:1.0/60.0 target:self selector:#selector(targetMethod:) userInfo:nil repeats: YES];
}
-(void) targetMethod: NSTimer * theTimer {
... update label
}

Related

Changing the random image

With the help of a few threads here I created a slideshow that starts as soon as my view loads
However I am trying to make a slight modification where, I want the images to be random Not showing in the order in the array or in any particular order. This is my codde
-(void)viewDidAppear:(BOOL)animated
{
NSArray *myImages=[NSArray arrayWithObjects:
[UIImage imageNamed:#"Pitt Bull"],
[UIImage imageNamed:#"German Sherpard"],
[UIImage imageNamed:#"Pincer"],
nil];
int indexed=arc4random()%[myImages count];
UIImage *image=[myImages objectAtIndex:indexed];
NSArray *imageAr=[NSArray arrayWithObject:image];
[NSTimer scheduledTimerWithTimeInterval:12.0
target:self
selector:#selector(viewDidAppear:)
userInfo:Nil
repeats:YES];
[self.kenView animageWithImages:imageAr
transitionDuration:12
loop:YES
isLandscape:YES];
}
However it only works once. it loads a random picture at the start, but after that it keeps loading the same image. I can see that is because indexed is only assigned an integer when the view "did appear" . I was wondering if there was another way too select a new random number since I am not using a button/action as I saw many of other members doing. OR a better way of accomplishing this.
Thank you
You may want to try this function, + (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats from NSTimer.
For example, in ViewDidLoad
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(showImage:) userInfo:nil repeats:YES];
and declare a function
- (void)showImage:(NSTimer*)timer
{
// your code to generate random index and animate image transition
}
if for some reason, you want to stop the timer
[timer invalidate];
Update
To avoid the timer messing up issue, trigger timer inside showImage, in ViewDidLoad, do [self showImage]
- (void)showImage
{
// your code to generate random index and animate image transition
// trigger the timer when the transition is finished
// You can leverage the method animateWithDuration:animations:completion:
// from UIView
[UIView animateWithDuration:12
animations:^(){
// image transition
}
completion:^(BOOL finished){
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(showImage) userInfo:nil repeats:NO];
}]
}
This should provide you the idea.
Consider using this method to randomly shuffle the elements of your array at startup.

Objective c : How to set time and progress of uiprogressview dynamically?

Say I have a UIProgressBar with size (394,129,328,9) and I increased the height with
CGAffineTransform transform = CGAffineTransformMakeScale(1.0f, 3.0f);
PgView.transform = transform;
What I need to implement is : If I have 5 minute time,the progressView should be filled with a certain amount and totally filled at the end of 5 minute. Same for 1 minute and 30 minutes too.
I am implementing like this :
-(void)viewWillAppear:(BOOL)animated
{
CGAffineTransform transform = CGAffineTransformMakeScale(1.0f, 3.0f);
PgView.transform = transform;
recievedData = 0.01;
xpectedTotalSize = 1.0;
PgView.progress = 0.0;
[self performSelectorOnMainThread:#selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO];
}
- (void)makeMyProgressBarMoving
{
float actual = [PgView progress];
if (actual < 1)
{
PgView.progress = actual + ((float)recievedData/(float)xpectedTotalSize);
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(makeMyProgressBarMoving) userInfo:nil repeats:NO];
}
else{
}
}
And it works. But I want to implement progress and time interval dynamically? Any idea??
Thanks in advance.
It's difficult to understand your intention. As I suppose, you want to update the progress bar only if new values are available instead of updating with a fixed timer interval.
This would result in the simple answer: update your progress bar whenever you change the value of 'recievedData'. So, the method 'makeMyProgressBarMoving' doesn't need a timer. Also, you don't need to remember the 'actual' value. You can directly assign the 'receivedData/xpectedTotalSize' to the progress bar.
- (void) updateProgressBar
{
PgView.progress = ((float)receivedData/(float)xpectedTotalSize);
}
- (void) updateReceivedData
{
if (receivedData < 20)
receivedData += 1.0;
else
receivedData += 10.0;
[self updateProgressBar];
}
-(void)viewWillAppear:(BOOL)animated
{
receivedData = 0.0;
xpectedTotalSize = 100.0;
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(updateReceivedData) userInfo:nil repeats:YES];
}
Now, a timer is still used for demonstration to call 'updateReceivedData' which just increments 'receivedData' and calls 'updateProgressBar'. As you see, 'updateReceivedData' does not increment linear, again just for demonstration. If 'updateReceivedData' would be called on demand instead by the timer then also the progress bar would be updated on demand. Now it's just an issue of how and when you want to update your receivedData. It's not an issue regarding progress bars.

how to stop repeat timer?

I am a beginner when it comes to iOS App development. I want to move a label from left to right until it reaches half the screen width - i.e. the label should move by 240px (the label moves left to right like a marquee).
I have used NSTimer and I want to stop the timer when the label reaches half the view's width.
I have used the following code but it moves the label out of the view:
- (void)viewDidLoad {
[super viewDidLoad];
timer = [[NSTimer scheduledTimerWithTimeInterval:0.09 target:self selector:#selector(time:) userInfo:nil repeats:YES] retain];
}
- (void)time:(NSTimer *)theTimer {
label.center = CGPointMake(label.center.x+3.5, label.center.y);
NSLog(#"point:%#", label);
if (label.center.x < - (label.bounds.size.width/2)) {
label.center = CGPointMake(320+(label.bounds.size.width/2), label.center.y);
}
}
How can I solve this, please?
If you want to stop the repeating timer, you can use
if (/*You label is in position*/)
[myTimer invalidate];
But that's not the normal way to do animation in iOS, try this instead:
CGRect endFrame = /*The frame of your label in end position*/
[UIView animateWithDuration:0.5 animations:^{ myLabel.frame = endFrame;}];
To stop a timer, do [timer invalidate].
You can't "pause" a timer, so once you do this you'll need to call another timer.
correct way to invalidate your timer is
[myTimer invalidate];
myTimer = nil;

Xcode Objective-C | iOS: delay function / NSTimer help?

So I'm developing my first iOS application and I need help..
Simple program for now, I have about 9 buttons and when I press the first button, or any button, I just want the first button to highlight for 60 milliseconds, unhighlight, second button highlights, wait 60 milliseconds, unhighlight and so on for the rest of the buttons so it looks like a moving LED.
I've looked tried sleep/usleep but once that sleep duration is done it seems like it skips the highlight/unhighlight all together.
For example:
- (void) button_circleBusy:(id)sender{
firstButton.enabled = NO;
sleep(1);
firstButton.enabled = YES;
and so on for the rest of the buttons. It DOES delay, but it doesn't delay the "firstButton.enabled = NO;". I have a picture for each button's "disabled state" and I never see it.
Any help's appreciated! I've looked into NSTimer but I was unsure on how to implement it.
Thanks.
-Paul
sleep doesn't work because the display can only be updated after your main thread returns to the system. NSTimer is the way to go. To do this, you need to implement methods which will be called by the timer to change the buttons. An example:
- (void)button_circleBusy:(id)sender {
firstButton.enabled = NO;
// 60 milliseconds is .06 seconds
[NSTimer scheduledTimerWithTimeInterval:.06 target:self selector:#selector(goToSecondButton:) userInfo:nil repeats:NO];
}
- (void)goToSecondButton:(id)sender {
firstButton.enabled = YES;
secondButton.enabled = NO;
[NSTimer scheduledTimerWithTimeInterval:.06 target:self selector:#selector(goToThirdButton:) userInfo:nil repeats:NO];
}
...
int64_t delayInSeconds = 0.6;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
do something to the button(s)
});
Less code is better code.
[NSThread sleepForTimeInterval:0.06];
Swift:
Thread.sleep(forTimeInterval: 0.06)
A slightly less verbose way is to use the performSelector: withObject: afterDelay:
which sets up the NSTimer object for you and can be easily cancelled
So continuing with the previous example this would be
[self performSelector:#selector(goToSecondButton) withObject:nil afterDelay:.06];
More info in the doc
Try
NSDate *future = [NSDate dateWithTimeIntervalSinceNow: 0.06 ];
[NSThread sleepUntilDate:future];
I would like to add a bit the answer by Avner Barr. When using int64, it appears that when we surpass the 1.0 value, the function seems to delay differently. So I think at this point, we should use NSTimeInterval.
So, the final code is:
NSTimeInterval delayInSeconds = 0.05;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
//do your tasks here
});
[NSTimer scheduledTimerWithTimeInterval:.06 target:self selector:#selector(goToSecondButton:) userInfo:nil repeats:NO];
Is the best one to use. Using sleep(15); will cause the user unable to perform any other actions. With the following function, you would replace goToSecondButton with the appropriate selector or command, which can also be from the frameworks.

Cocoa Image Gallery Window

I have a HUD panel in an app and I want to be able to take a set of images and show each image on the panel for a few seconds before displaying the next image. I'm very new to Cocoa and am having trouble implementing this so some pointers would be welcomed. Here's what I'm currently trying:
[newShots enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop)
{
//get url
NSURL *imageUrl = [[NSURL alloc] initWithString:[obj objectForKey:#"image_url"]];;
//get image from url
NSImage *image = [[NSImage alloc] initWithContentsOfURL:imageUrl];
//set it to shot panel
[shotPanelImageView setImage:image];
//clean up
[imageUrl release];
[image release];
//set needs refresh
[shotPanelImageView setNeedsDisplay:YES];
//sleep a few before moving to next
[NSThread sleepForTimeInterval:3.0];
}];
As you can see I'm just looping the info for each image, grabbing it via URL, setting it to the view, and then calling thread sleep for a few seconds before moving on. The issue is that the view will not redraw with the new image when it is assigned. I thought that setNeedsDisplay:YES would force a redraw but only the first image in the collection is ever displayed. I've put in NSLog()'s and debugged and I know for sure the enumeration is working correctly as I can see the new image information being set as it should.
Is there something I'm missing or is this a completely wrong way of going about solving this problem?
Thanks,
Craig
You are sleeping the main thread, which I'm pretty sure is not a good idea. I suggest that the Cocoa way to do what you want is to use a timer. In place of your code above:
[NSTimer scheduledTimerWithTimeInterval:3.0
target:self
selector:#selector(showNextShot:)
userInfo:nil
repeats:YES];
(The userInfo parameter allows you to pass along an arbitrary object that you want to use when the timer fires, so you could potentially use this to keep track of the current index as an NSNumber, but it would have to be wrapped in a mutable container object, because you can't set it later.)
Then put the code from your block into the method called by the timer. You'll need to make an instance variable for the current index.
- (void)showNextShot:(NSTimer *)timer {
if( currentShotIdx >= [newShots count] ){
[timer invalidate]; // Stop the timer
return; // Also call another cleanup method if needed
}
NSDictionary * obj = [newShots objectAtIndex:currentShotIdx];
// Your code...
currentShotIdx++;
}
To avoid the initial 3 sec delay caused by using a timer, you can call the same method your timer uses, right before you set it up:
[self showNextShot:nil]
[NSTimer scheduled...
Or could also schedule a non-repeating timer to fire as soon as possible (if you really wanted to use userInfo):
[NSTimer scheduledTimerWithTimeInterval:0.0
...
repeats:NO];
EDIT: I forgot about -initWithFireDate:interval:target:selector:userInfo:repeats:!
NSTimer *tim = [[NSTimer alloc] initWithFireDate:[NSDate date]
interval:3.0
target:self
selector:#selector(showNextShot:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:tim
forMode:NSDefaultRunLoopMode];
[tim release];