I make a Voca App.
After playing voice file and showing English text, it shows the meaning label.
So, I want to hide label texts before playing next voice file.
I have problem.df
These labels are not hidden.
Approaching the label at timer, it can's renewal string of label.
What is the problem?
Help me, please!
- (void)showLabel{
Word *word = [wordArray objectAtIndex:selectedIndex];
[simpleMeaning setText:word.mean];
NSTimer *timer2 = [[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(hideLabel) userInfo:nil repeats:NO] retain];
[timerArray addObject:timer2];
[timer2 release];
timer2 = nil;
}
- (void)hideLabel{
[simpleMeanig setText:#" "];
++selectedIndex;
[self filePlay];
}
I'm wondering if the call to filePlay is blocking the UI update (hard to tell without seeing the guts of filePlay).
This is just a guess, but instead of:
[self filePlay];
try:
[self performSelectorOnMainThread:(#selector(filePlay) withObject:nil waitUntilDone:NO];
This will defer the call to filePlay until after the current event (as a result of the timer firing) has been processed (which should in turn should allow the UI to refresh itself).
Related
I'm wondering the best approach to take for this.
The example app is:- I have a text field and button. click the button, initiates a task to update the text field. But the text field needs to be updated on a timer (or in background), say every 1 sec, but I only need the timer to run for say 5 secs, populating a random piece of text for example.
This should give the impression that the text box is displaying random words every sec, then after the 5 secs has completed, the timer can stop and the last value remains in the text box.
But I also want to detect the stop event and then pick up the value in the text field and perform another action.
Finally the question :-
Should I use Timer events, or operations and queues ? Not sure which approach is best.
Yes, use a timer in this way, repeats:YES is what you need:
[NSTimer scheduledTimerWithTimeInterval:1 target:self
selector:#selector(ChangeText) userInfo:nil repeats:YES];
- (void) ChangeText
{
_textfield.text = [nsstring stringwithformat:#"%#%#", _textfield.text, _yourstring];
}
Yes , above answer is correct, just need some small changes according to your question...
count = 0;
[NSTimer scheduledTimerWithTimeInterval:1 target:self
selector:#selector(ChangeText) userInfo:nil repeats:YES];
- (void) ChangeText
{
if (count < 5)
{
_textfield.text = [nsstring stringwithformat:#"%#%#", _textfield.text, _yourstring];
}
else
{
//Start your next event here;
}
NSTimer able to work only on main thread, then you don't need to expect that it will fire if it launched in background.
Also I think it's basically question of good architecture - don't you want try to handle events to update your textfield? For example, handle event when some task is finished or displayed value changed, then use delegate/block/NSNotification to receive event and update UI.
I am calling this takePicture function 5 times because i neeed to take 5 picture on on click(Burst Mode)
for(count=0;count<5;count++)
{
[picker takePicture];
[NSThread sleepForTimeInterval:0.5];
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate: [NSDate date]];
}
I am getting this error UIImagePickerController: ignoring request to take picture; image is already being captured or camera not yet ready.
Not sure but i think camera not yet ready ... Because you are trying to capture images continuously.... I think you will have to delay for few seconds before call take picture method again..... Dont do it in for loop i would like to suggest you please use NSTimer instead of looping.
something like this -
Declare
-(void)startTimer;
and
int count;
in your .h class then see below code -
-(void)yourTakePictureButtonClick:(id)sender
{
[self startTimer];
}
-(void)startTimer
{
count = 0;
yourTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(myFunctionForClickImage) userInfo:nil repeats:YES];
}
-(void)myFunctionForClickImage
{
[picker takePicture];
count ++;
if (count < 5)
{
[yourTimer invalidate];
}
}
Hi H2SO4 (Nice Name han)
The most probable reason seems to be the absence of the required key in your info.plist file. You will need to configure UIRequiredDeviceCapabilities. Also, you must implement the delegate object. For details, have a look at
http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/CameraAndPhotoLib_TopicsForIOS/Articles/TakingPicturesAndMovies.html#//apple_ref/doc/uid/TP40010406.
HTH,
Another thing you should release your resources in every call inside loop.
You can delay with following.
[picker performSelector:#selector(takePicture) withObject:nil afterDelay:2.0];
For more you can visit...
http://highoncoding.com/Articles/856_Building_Instagram_for_the_iPhone_Part_2.aspx
I'm working on a very simple iPhone game that involves choosing the right colored button as many times in a row based on a randomized voice prompt. I have it set up so that if the button is one color and gets clicked, it always goes to a hard-coded color every time (e.g. if you click red, it always turns blue). The color change method is set up in an IBOutlet. I have a timer set up in a while loop, and when the timer ends it checks if the player made the right selection. The problem is that the button color change does not occur until after the timer runs out, and this causes a problem with the method used to check the correct answer. Is there a way to make this color change happen instantly? From what I've searched I know it has something to do with storyboard actions not occurring until after code executes, but I haven't found anything with using a timer. Here is a section of the method that calls the timer if the answer is correct:
BOOL rightChoice = true;
int colorNum;
NSDate *startTime;
NSTimeInterval elapsed;
colorNum = [self randomizeNum:middle];
[self setTextLabel:colorNum];
while (rightChoice){
elapsed = 0.0;
startTime = [NSDate date];
while (elapsed < 2.0){
elapsed = [startTime timeIntervalSinceNow] * -1.0;
NSLog(#"elapsed time%f", elapsed);
}
rightChoice = [self correctChoice:middleStatus :colorNum];
colorNum = [self randomizeNum:middle];
}
One of two things stood out
You're using a while loop as a timer, don't do this - the operation is synchronous.
If this is run on the main thread, and you code doesn't return, your UI will update. The mantra goes: 'when you're not returning you're blocking.'
Cocoa has NSTimer which runs asynchronously - it is ideal here.
So let's get to grips with NSTimer (alternatively you can use GCD and save a queue to an ivar, but NSTimer seems the right way to go).
Make an ivar called timer_:
// Top of the .m file or in the .h
#interface ViewController () {
NSTimer *timer_;
}
#end
Make some start and stop functions. How you call these is up to you.
- (void)startTimer {
// If there's an existing timer, let's cancel it
if (timer_)
[timer_ invalidate];
// Start the timer
timer_ = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:#selector(onTimerFinish:)
userInfo:nil
repeats:NO];
}
- (void)onTimerFinish:(id)sender {
NSLog(#"Timer finished!");
// Clean up the timer
[timer_ invalidate];
timer_ = nil;
}
- (void)stopTimer {
if (!timer_)
return;
// Clean up the timer
[timer_ invalidate];
timer_ = nil;
}
And now
Put your timer test code in the onTimerFinish function.
Make an ivar that stores the current choice. Update this ivar when a choice is made and make the relevant changes to the UI. Call stopTimer if the stop condition is met.
In the onTimerFinished you can conditionally call and startTimer again if you desire.
Hope this helps!
I'm trying to create a UILabel which will inform the user of what is going on while he waits. However the UILabel always delay its text update until after the system goes idle again.
The process:
[infoLine performSelectorOnMainThread:#selector(setText:) withObject:#"Calculating..." waitUntilDone:YES];
[distanceManager calc]; // Parses a XML and does some calculations
[infoLine performSelectorOnMainThread:#selector(setText:) withObject:#"Idle" waitUntilDone:YES];
Should not waitUntilDone make this happen "immediately"?
If you are doing this on the main UI thread, don't use waitUntilDone. Do a setText, setNeedsDisplay on the full view, set a NSTimer to launch what you want to do next starting 1 millisecond later, then return from your function/method. You may have to split your calculation up into chucks that can be called separately by the timer, maybe a state machine with a switch statement (select chunk, execute chunk, increment chunk index, exit) that gets called by the timer until it's done. The UI will jump in between your calculation chunks and update things. So make sure your chunks are fairly short (I use 15 to 200 milliseconds).
Yes waitUntilDone makes the setText: happen immediately, but setting the label's text does not mean the screen is updated immediately.
You may need to call -setNeedsDisplay or even let the main run loop tick once before the screen can be updated.
Here's a useful function I added to a subclass of UIViewController. It performs the selector in the next run loop. It works, but do you think I should make NSTimer *timer an instance variable since it's likely this method will be called more than once.
- (void)scheduleInNextRunloopSelector:(SEL)selector {
NSDate *fireDate = [[NSDate alloc] initWithTimeIntervalSinceNow:0.001]; // 1 ms
NSTimer *timer = [[NSTimer alloc]
initWithFireDate:fireDate interval:0.0 target:self
selector:selector userInfo:nil repeats:NO];
[fireDate release];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[timer release];
}
Use performSelector:(SEL) withObject:(id) afterDelay:(NSTimeInterval):
self.infoLine.text = #"Calculating...";
[self performSelector:#selector(likeABoss) withObject:nil afterDelay:0.001];
//...
-(void) likeABoss {
// hard work here
self.infoLine.text = #"Idle";
}
I have an int which defines the objectAtIndex, which gives it to the string, which then displays it in the UILabel, HOWEVER, when I modify the array (add a word to it in this case) when I have the UILabel go through the array it only displays the odd ones. I have done an NSLog and found out that it DOES PASS EVERY SINGLE THING to the string, but the Label isn't displaying every single one, it only does it the first time, then I modify the array, and it only does odd
edit: the code:
- (void) stuff {
NSArray *indivwords = [sentence componentsSeparatedByString:#" "];
count = [indivwords count]; //count=int
if (i < count) {
NSString *chunk = [indivwords objectAtIndex:i];
[word setText:chunk];
NSLog(chunk);
i++;
} else {
word.textColor = [UIColor greenColor];
[word setText:#"DONE"];
}
}
All of this is being controlled by an NSTimer, which sets it off based on a slider value. Also i is set to 0 in the IBAction
The IBAction code:
word.textColor = [UIColor whiteColor];
[timer invalidate];
i = 0;
speedd = (1/speed.value)*60;
timer = [NSTimer scheduledTimerWithTimeInterval:(speedd) target:self selector:#selector(stuff) userInfo:nil repeats:YES];
EDIT:
I fixed it! What I did was call this after i reached the count
-(void)stoptimer
{
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:(.01) target:self selector:#selector(empty) userInfo:nil repeats:YES];
}
empty is just a void with nothing in it, well, all I did was add a comment,
//don't look over here, nothing to see here, oh look at that
Somebody can close this if they want
You said the time interval of your NSTimer is controlled by a slider. Perhaps you are starting a new timer instance every time you change the slider value, so after a change you would have two timers running. The first one updates the label and increments i. The second one comes right after the first and finds i's value incremented, so it displays the next chunk instead of the current one.
Count the instances of your timer - NSLog the timer in the timer callback and compare the results - it may be that you're firing more than one.
My guess is that you have two different actions calling this method, when you think there should be one. I'd put a break point in there, and see if it stops where you think it should.