Adding Stop and Reset buttons to NSTimer [duplicate] - objective-c

This question already has answers here:
Stop and Reset NSTimer
(2 answers)
Closed 9 years ago.
I have created a NSTimer that simply times minutes and I am wishing to add a stop and reset button to it. So far my code looks like this:
#implementation TimeController
int timeTick = 0;
NSTimer *timer;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
labelTime.text = #"0";
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startTimer:(id)sender {
[timer invalidate];
timer= [NSTimer scheduledTimerWithTimeInterval:60.0 target:(self) selector:(#selector(tick)) userInfo:(nil) repeats:(YES)];
}
-(void)tick{
timeTick++;
NSString *timeString = [[NSString alloc] initWithFormat:#"%d", timeTick];
labelTime.text = timeString;
}
#end
Thanks in advance!

Your timeTick and timer are actually globals which is probably not what you intended. You should probably declare them as instance variables. This will allow you to have multiple instances of your TimeController and have them all count independently.
Then your code may look something like this
#interface TimeController ()
#property (nonatomic, assign) NSInteger minutes;
#property (nonatomic, strong) NSTimer *timer;
#end
#implementation TimeController
- (void)viewDidLoad
{
[super viewDidLoad];
[self updateMinuteLabel];
}
- (IBAction)startTimer
{
[self.timer invalidate];
self.timer = [NSTimer scheduledTimerWithTimeInterval:60.0
target:self
selector:#selector(tick)
userInfo:nil
repeats:YES];
}
- (IBAction)stopTimer
{
[self.timer invalidate];
}
- (IBAction)resetTimer
{
self.minutes = 0;
[self updateMinuteLabel];
}
- (void)tick
{
self.minutes += 1;
[self updateMinuteLabel];
}
- (void)updateMinuteLabel
{
self.minuteLabel.text = [NSString stringWithFormat:#"%d", self.minutes];
}
#end

Related

Use timer in a UIImageView Subclass

I want to change the picture of my custom UIImageView Subclass by a timer. But it doesn't work. Can you help me?
This is my code:
-(id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self update];
}
return self;
}
-(void)update {
self.image = [UIImage imageNamed:#"Green.png"];
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(change) userInfo:nil repeats:YES];
}
-(void)change {
self.image = [UIImage imageNamed:#"Red.png"];
}
Thanks!
use image property also to assign any image to imageView small rectification see below code.
Also do not give variable name same as its class property.
-(void)update {
self.image.image = [UIImage imageNamed:#"Green.png"];
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(change) userInfo:nil repeats:YES];
}
-(void)change {
self.image.image = [UIImage imageNamed:#"Red.png"];
}
self.image.image peoperty added here
Edit:
change your property from UIImage to UIImageView like see below
#property (strong, nonatomic) IBOutlet UIImageView *image;
.h Header file
#import <UIKit/UIKit.h>
#interface orientation : UIViewController
#property (strong, nonatomic) IBOutlet UIImageView *image;
#end
.m Message file
#import "orientation.h"
#interface orientation ()
#end
#implementation orientation
- (void)viewDidLoad {
[super viewDidLoad];
[self update];
// Do any additional setup after loading the view.
}
-(void)update {
self.image.image = [UIImage imageNamed:#"investment1.png"];
[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(change) userInfo:nil repeats:YES];
}
-(void)change {
self.image.image = [UIImage imageNamed:#"logout.png"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end

Change array of images with NSTimer

I want to implement a auto change image gallery. here is my code in the controller. i have a uiimageview named image. i want to link the array of image to my image view to let it auto change after a few seconds. What should i do??
- (void)viewDidLoad{
[super viewDidLoad];
[self performSelector:#selector(changeImage) withObject:nil afterDelay:2];
}
-(void)changeImage {
NSArray *images = [NSArray arrayWithObjects:[UIImage imageNamed:#"animated-fish-1.jpg"], [UIImage imageNamed:#"tumblr_7"], [UIImage imageNamed:#"th_nature_4.jpg"],nil];
image.animationImages = images;
// how to let the array of image load and link to the perform selector??
// what should i continue from here?
}
Store the images in an ivar
#interface YourClass : SomeSuperClass
#property (nonatomic, strong) NSArray *images;
#end
Don't start the timer in viewDidLoad as the view will not be on the screen yet so there is no point - move it to viewDidAppear:
- (void)viewDidLoad
{
[super viewDidLoad];
self.images = #[ ... ]; // or pass these into the class
self.imageView.image = self.images[0];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[NSTimer scheduledTimerWithTimeInterval:2
target:self
selector:#selector(changeImage:)
userInfo:nil
repeats:YES];
}
-(void)changeImage:(NSTimer *)timer
{
NSInteger currentIndex = [self.images indexOfObject:self.imageView.image];
NSInteger nextIndex = (currentIndex + 1) % self.images.count;
self.imageView.image = self.images[nextIndex];
// If for any reason you need to cancel the image rotation
if ([self shouldCancelImageRotation]) {
[timer invalidate];
}
}
To animate the images using timer, try this
- (void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(animateImages)
userInfo:nil
repeats:YES];
imageCount = 1;
}
-(void)animateImages
{
imageCount = imageCount + 1;
NSString *imageName = [NSString stringWithFormat:#"image%i.png"];
[theImage setImage:[UIImage imageNamed:imageName]];
}
You should use NSTimer, per example, you can use this method :
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html#//apple_ref/occ/clm/NSTimer/scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
This method allow you to define a selector to use and repeats every x seconds
try like this ,
take one global varaible index
- (void)viewDidLoad{
[super viewDidLoad];
index=0;
NSArray *images = [NSArray arrayWithObjects:[UIImage imageNamed:#"animated-fish-1.jpg"], [UIImage imageNamed:#"tumblr_7"], [UIImage imageNamed:#"th_nature_4.jpg"],nil];
imageview.image = [images objectAtIndex:index];
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(changeImage) userInfo:nil repeats:YES];
}
-(void)changeImage {
index++;
if(index==[images count]){
index=0;
}
imageview.image = [images objectAtIndex:index];
}

How to fix: Incomplete Implementation

How can I fix the problem of Incomplete Implementation?
View of Controller.m :
#import "Quiz_GameViewController.h"
#implementation Quiz_GameViewController
#synthesize theQuestion, timer, theScore, theLives, answerOne, answerTwo, answerThree, answerFour, theQuiz
;
-(void)askQuestion
{
// Unhide all the answer buttons.
[answerOne setHidden:NO];
[answerTwo setHidden:NO];
[answerThree setHidden:NO];
[answerFour setHidden:NO];
// Set the game to a "live" question (for timer purposes)
questionLive = YES;
// Set the time for the timer
time = 8.0;
// Go to the next question
questionNumber = questionNumber + 1;
// We get the question from the questionNumber * the row that we look up in the array.
NSInteger row = 0;
if(questionNumber == 1)
{
row = questionNumber - 1;
}
else
{
row = ((questionNumber - 1) * 6);
}
// Set the question string, and set the buttons the the answers
NSString *selected = [theQuiz objectAtIndex:row];
NSString *activeQuestion = [[NSString alloc] initWithFormat:#"Question: %#", selected];
[answerOne setTitle:[theQuiz objectAtIndex:row+1] forState:UIControlStateNormal];
[answerTwo setTitle:[theQuiz objectAtIndex:row+2] forState:UIControlStateNormal];
[answerThree setTitle:[theQuiz objectAtIndex:row+3] forState:UIControlStateNormal];
[answerFour setTitle:[theQuiz objectAtIndex:row+4] forState:UIControlStateNormal];
rightAnswer = [[theQuiz objectAtIndex:row+5] intValue];
// Set theQuestion label to the active question
theQuestion.text = activeQuestion;
// Start the timer for the countdown
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
[selected release];
[activeQuestion release];
}
-(void)updateScore
{
// If the score is being updated, the question is not live
questionLive = NO;
[timer invalidate];
// Hide the answers from the previous question
[answerOne setHidden:YES];
[answerTwo setHidden:YES];
[answerThree setHidden:YES];
[answerFour setHidden:YES];
NSString *scoreUpdate = [[NSString alloc] initWithFormat:#"Score: %d", myScore];
theScore.text = scoreUpdate;
[scoreUpdate release];
// END THE GAME.
NSInteger endOfQuiz = [theQuiz count];
if((((questionNumber - 1) * 6) + 6) == endOfQuiz)
{
// Game is over.
if(myScore > 0)
{
NSString *finishingStatement = [[NSString alloc] initWithFormat:#"Game Over!\nNice Game \nYou scored %i!", myScore];
theQuestion.text = finishingStatement;
[finishingStatement release];
}
else
{
NSString *finishingStatement = [[NSString alloc] initWithFormat:#"Game Over!\n You're terrible! \nYou scored %i.", myScore];
theQuestion.text = finishingStatement;
[finishingStatement release];
}
theLives.text = #"";
// Make button 1 appear as a reset game button
restartGame = YES;
[answerOne setHidden:NO];
[answerOne setTitle:#"Restart game!" forState:UIControlStateNormal];
}
else
{
// Give a short rest between questions
time = 3.0;
// Initialize the timer
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countDown) userInfo:nil repeats:YES];
}
}
-(void)countDown
{
// Question live counter
if(questionLive==YES)
{
time = time - 1;
theLives.text = [NSString stringWithFormat:#"Time remaining: %i!", time];
if(time == 0)
{
// Loser!
questionLive = NO;
theQuestion.text = #"HAHA now you lost alot of points!";
myScore = myScore - 1000;
[timer invalidate];
[self updateScore];
}
}
// In-between Question counter
else
{
time = time - 1;
theLives.text = [NSString stringWithFormat:#"Next question coming in...%i!", time];
if(time == 0)
{
[timer invalidate];
theLives.text = #"";
[self askQuestion];
}
}
if(time < 0)
{
[timer invalidate];
}
}
- (IBAction)buttonOne
{
if(questionNumber == 0){
// This means that we are at the startup-state
// We need to make the other buttons visible, and start the game.
[answerTwo setHidden:NO];
[answerThree setHidden:NO];
[answerFour setHidden:NO];
[self askQuestion];
}
else
{
NSInteger theAnswerValue = 1;
[self checkAnswer:(int)theAnswerValue];
if(restartGame==YES)
{
// Create a restart game function.
}
}
}
- (IBAction)buttonTwo
{
NSInteger theAnswerValue = 2;
[self checkAnswer:(int)theAnswerValue];
}
- (IBAction)buttonThree
{
NSInteger theAnswerValue = 3;
[self checkAnswer:(int)theAnswerValue];
}
- (IBAction)buttonFour
{
NSInteger theAnswerValue = 4;
[self checkAnswer:(int)theAnswerValue];
}
// Check for the answer (this is not written right, but it runs)
-(void)checkAnswer:(int)theAnswerValue
{
if(rightAnswer == theAnswerValue)
{
theQuestion.text = #"Daaamn";
myScore = myScore + 50;
}
else
{
theQuestion.text = #"hahaha!";
myScore = myScore - 50;
}
[self updateScore];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
questionLive = NO;
restartGame = NO;
theQuestion.text = #"Think you can do it?";
theScore.text = #"Score:0";
theLives.text = #"";
questionNumber = 0;
myScore = 0;
myLives = 0;
[answerOne setTitle:#"I think i can!" forState:UIControlStateNormal];
[answerTwo setHidden:YES];
[answerThree setHidden:YES];
[answerFour setHidden:YES];
[self loadQuiz];
}
-(void)loadQuiz
{
// This is our forced-loaded array of quiz questions.
// FORMAT IS IMPORTANT!!!!
// 1: Question, 2 3 4 5: Answers 1-4 respectively, 6: The right answer
// THIS IS A TERRIBLE WAY TO DO THIS. I will figure out how to do nested arrays to make this better.
NSArray *quizArray = [[NSArray alloc] initWithObjects:#"Who is the president in USA?",#"Me",#"Obama",#"George Bush",#"Justin Bieber",#"2",
#"Capital in Norway?", #"Bergen", #"Trondheim", #"Oslo", #"Bærum", #"3",
#"The right answer is 3!", #"41", #"24", #"3", #"9", #"1",
#"Do I have a cat?", #"Yes", #"No", #"No, you have a dog", #"No, you have a flying hamster", #"4",
#"Baba", #"Daba jaba?", #"Laba daba haba?", #"Saba daba gaba?", #"Haba haba?", #"4",
nil];
self.theQuiz = quizArray;
[quizArray release];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[theQuestion release];
[theScore release];
[theLives release];
[answerOne release];
[answerTwo release];
[answerThree release];
[answerFour release];
[theQuiz release];
[timer release];
[super dealloc];
}
#end
I'am new here and this is an example script from the internet...I use it to learn the language Objective-C and Cocoa...ViewController.h :
#import <UIKit/UIKit.h>
#interface Quiz_GameViewController : UIViewController {
IBOutlet UILabel *theQuestion;
IBOutlet UILabel *theScore;
IBOutlet UILabel *theLives;
IBOutlet UIButton *answerOne;
IBOutlet UIButton *answerTwo;
IBOutlet UIButton *answerThree;
IBOutlet UIButton *answerFour;
NSInteger myScore;
NSInteger myLives;
NSInteger questionNumber;
NSInteger rightAnswer;
NSInteger time;
NSArray *theQuiz;
NSTimer *timer;
BOOL questionLive;
BOOL restartGame;
}
#property (retain, nonatomic) UILabel *theQuestion;
#property (retain, nonatomic) UILabel *theScore;
#property (retain, nonatomic) UILabel *theLives;
#property (retain, nonatomic) UIButton *answerOne;
#property (retain, nonatomic) UIButton *answerTwo;
#property (retain, nonatomic) UIButton *answerThree;
#property (retain, nonatomic) UIButton *answerFour;
#property (retain, nonatomic) NSArray *theQuiz;
#property (retain, nonatomic) NSTimer *timer;
-(IBAction)buttonOne;
-(IBAction)buttonTwo;
-(IBAction)buttonThree;
-(IBAction)buttonFour;
-(void)checkAnswer;
-(void)askQuestion;
-(void)updateScore;
-(void)loadQuiz;
-(void)countDown;
#end
In your headerfile, you have declared the method -(void)checkAnswer, while in the .m file you have declared it -(void)checkAnswer:(int)theAnswerValue.
This means that your .m file is looking for a method -(void)checkAnswer, which does not exist, and it yields an Incomplete implementation warning. Simply change your declaration in the .h file to - (void)checkAnswer:(int)theAnswerValue, and you'll be fine.
See in .h you have (method with no parameters):
-(void)checkAnswer;
and in .m you have (method with one int parameter):
-(void)checkAnswer:(int)theAnswerValue
Incomplete Implementation means you declared something in .h but didn't implement that in .m.
The signature of checkAnswer is different in you .h and .m
in Quiz_GameViewController.h:
-(void)checkAnswer;
in Quiz_GameViewController.m
-(void)checkAnswer:(int)theAnswerValue
FIX : Change the Quiz_GameViewController.h to:
- (void)checkAnswer:(int)theAnswerValue,

NSArray causes EXC_BAD_ACCESS

I declare an NSArray in one class like this:
.h
#interface HTTP : NSObject {
NSArray *listOfProfiles;
}
#property (nonatomic, retain) NSArray *listOfProfiles;
.m
-(id) init {
if ((self = [super init])) {
listOfProfiles = [[NSArray alloc] init];
}
return self;
}
-(void) someMethod {
...
case GET_LIST_OF_PROFILES:
listOfProfiles = [result componentsSeparatedByString:#"^-^"];
NSLog(#"first break: %#",[listOfProfiles objectAtIndex:0]);
break;
...
}
I can access it here just fine, then when I try to access it in another class after creating an object I receive the error EXC_BAD_ACCESS and the debugger goes to main.m:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
http = [[HTTP alloc] init];
[http createProfileArray];
profileListDelay = [[NSTimer alloc] init];
profileListDelay = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(profileListSelector) userInfo:nil repeats:YES];
}
- (void) profileListSelector
{
if (http.activityDone)
{
// http.listofprofiles mem leak?
for (int i = 0; i < http.listOfProfiles.count; i++)
{
NSLog(#"%#",[http.listOfProfiles objectAtIndex:i]);
}
[profileListDelay invalidate];
profileListDelay = nil;
}
}
I'm thinking it's a memory issue maybe, but I could be completely wrong.
It is a memory issue
It is in someMethod
-(void) someMethod {
...
case GET_LIST_OF_PROFILES:
listOfProfiles = [result componentsSeparatedByString:#"^-^"];
NSLog(#"first break: %#",[listOfProfiles objectAtIndex:0]);
break;
...
}
componentsSeparatedByString: returns an autoreleased object
Since you declared the array as a retain property, you should update it like so:
self.listOfProfiles = [result componentsSeparatedByString:#"^-^"];

NSTimer in NSOperation main method?

I want to set up a timer in -(void) main {} method of a NSOperation subclass. However, I the timer doesn't fire. I tried [[NSRunLoop currentRunLoop] addTimer:timer forMode: NSDefaultRunLoopMode]; with no success. Am I missing smth?
[EDIT] Will this run the timer on the main thread or on NSOperation's thread? (guessing NSOperation, but I'm not sure)
I found what need to be done to start the timer. I'll put it here if anyone ever needs it:
[[NSRunLoop currentRunLoop] run];
However, I'm still not sure if this will run in the NSOperation's thread.
I find that it is sometimes useful to wrap an NSOperation around a method that is fired by a timer, like you are doing, to take advantage of the dependencies, cancellation, and other features provided by the operations queue. It is however not usually necessary for the timer to run in a separate thread, nor is it usually necessary for the method that the timer invokes to be running in a background thread. In fact, most of the time it shouldn't run in a background thread because the method updates the UI. If this is true for you too a setup like this should work:
#import <Foundation/Foundation.h>
#interface TimerOperation : NSOperation {
#private
NSTimer* _timer;
}
#property (nonatomic, readonly) BOOL isExecuting;
#property (nonatomic, readonly) BOOL isFinished;
#end
(Add in your own state, custom constructor, etc.).
#implementation TimerOperation
#synthesize isExecuting = _executing;
#synthesize isFinished = _finished;
- (id) init {
if ((self = [super init])) {
_executing = NO;
_finished = NO;
}
return self;
}
- (void) dealloc {
[_timer release];
[super dealloc];
}
- (BOOL) isConcurrent {
return YES;
}
- (void) finish {
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
- (void) start {
if ([self isCancelled]) {
[self willChangeValueForKey:#"isFinished"];
_finished = YES;
[self didChangeValueForKey:#"isFinished"];
} else {
[self willChangeValueForKey:#"isExecuting"];
[self performSelectorOnMainThread:#selector(main)
withObject:nil
waitUntilDone:NO];
_executing = YES;
[self didChangeValueForKey:#"isExecuting"];
}
}
- (void) timerFired:(NSTimer*)timer {
if (![self isCancelled]) {
// Whatever you want to do when the timer fires
}
}
- (void) main {
_timer = [[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timerFired:)
userInfo:nil
repeats:YES] retain];
}
- (void) cancel {
[_timer invalidate];
[super cancel];
}
#end
Of course, if the main thread is blocked (for instance, because of a long database save) you will not see the timer firing, but most of the time this works fine.
You can use the same setup to deal with asynchronous APIs inside NSOperations.