I want to update the contents of this UITextView with this NSMutable array by adding some delay to it.
- (void)viewDidLoad{
[super viewDidLoad];
myArray = [[NSMutableArray alloc]initWithObjects:#"String1",#"String2",#"String3",#"String4", #"String5",..... nil];
int index = arc4random() % [myArray count];
myTextView.text = [myArray objectAtIndex:index];
I want to display this NSMutable array one after other with some delay in UITextView.
Is there some way to display array in UITextView with some delay.
Please help
Why you should use a timer
The correct way of doing this would be to use a repeating timer. The timer is configured to repeat and call a certain method every second.
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateText:)
userInfo:nil
repeats:YES];
Inside your (new) updateText method you would generate the random number and update the text.
- (void)updateText:(NSTimer *)theTimer {
int index = arc4random() % [myArray count];
myTextView.text = [myArray objectAtIndex:index];
}
This is a clean solution that is almost self documenting.
Why you shouldn't loop and perform after delay.
It is true that you could do this with performSelector:withObject:afterDelay: or dispatch_after() but it is a easy to get wrong and is the actual working solution is more complex and harder to understand.
If you think that you can just loop a certain number of times and inside call either of these then you are going to see something funny. Both these methods are asynchronous and will not wait for the call to be called. They are merely scheduling it to happen a specified time from "now".
What looping and calling asynchronous methods do
Loop
0 |----- 1s wait -----| |update|
1 |----- 1s wait -----| |update|
2 |----- 1s wait -----| |update|
3 |----- 1s wait -----| |update|
...
----------- time --------------------->
The result of this, as you can imagine, is that nothing will happen for one second. Then all the scheduled calls are going to happen all at once.
This is actually equal to performing the entire loop after one second.
|----- 1s wait -----| Loop:
0 |update|
1 |update|
2 |update|
3 |update|
...
----------- time --------------------->
You could make this work if you instead scheduled the next call after each update
|----- 1s wait -----| |update| |----- 1s wait -----| |update| ...
----------- time --------------------->
For this to happen you would have to schedule the next update in the previous update.
- (void)updateText {
int index = arc4random() % [myArray count];
myTextView.text = [myArray objectAtIndex:index];
[self performSelector:#selector(updateText)
withObject:nil
afterDelay:1.0];
}
This would do the exact same thing as the repeating timer but has two main disadvantages.
1) It is less intuitive.
In the timer example you would only have to read the timer code to understand that the text would update every second. In this case you would just call updateText. It is not intuitive by reading that code without looking at the implementation of updateText that this is a repeating process.
2) It gets even more complex if you want it to stop.
You can keep a pointer to an NSTimer and make it stop by simply calling [myTimer invalidate];. The code that uses either performSelector:... or dispatch_after() doesn't yet support it and if it was built to support that it would be even more complex and less intuitive.
Few ways to do, answer ranked according to my preference:
1.. You can use :
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)seconds target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)repeats
2.. Grand Central Dispatch will also be serve you.
Related
I have a program with 2 timer functions like this (p_maj_input and p_maj_output_motion are equal so the period of both timer is the same):
maj_input = timer('ExecutionMode','fixedRate','Period',p_maj_input,'TasksToExecute', ...
floor(Tmeasurement/p_maj_input)-1,'TimerFcn',{#time_append,p_maj_input,HR_all,freq_HR, ...
BVP_all,freq_BVP,TEMP_all,freq_TEMP,ACC_x_all,ACC_y_all,ACC_z_all,freq_ACC,EDA_all,freq_EDA, ...
folder_all,all_dir,num_dir}); start(maj_input);
maj_output_motion=timer('ExecutionMode','fixedRate','Period',p_maj_output_motion,'TasksToExecute', ...
floor(Tmeasurement/p_maj_output_motion)-1,'TimerFcn',{#output_motion_append, ...
freq_MOTION,freq_mvt_score,freq_walk,p_maj_output_motion,p_maj_output_walk,folder_all,all_dir,num_dir});%,'StartDelay',min(5,p_maj_output_motion)); %startDelay must be min 5 for walk detection start(maj_output_motion);
In each timer callback function there is a loop over subfolders contained in a folder that is selected at the beginning of the program.
output_motion_append(obj,event,freq_MOTION,freq_mvt_score,freq_walk,p_maj_output_motion,p_maj_output_walk,folder_all,all_dir,num_dir)
fprintf('motion %d\n',obj.TasksExecuted)
toc
for folder_index=1:num_dir
[folder_original,folder_fictive] = subfolderFunction(all_dir, folder_all, folder_index);
fileName=strcat(folder_fictive,'\ACC.csv');
[ACC_time, ACC_x, ACC_y, ACC_z] = loadValuesE4_acc(fileName);
% Motion Amount
[agitation,agitation_ts] = identifyAgitation(ACC_x,ACC_y,ACC_z,ACC_time);
agitation=agitation';
len1=length(agitation);
if len1<=freq_MOTION*p_maj_output_motion
i_init1=1;
elseif len1>freq_MOTION*p_maj_output_motion
i_init1=len1-freq_MOTION*p_maj_output_motion+1;
end
writematrix([agitation(i_init1:len1)],strcat(folder_fictive,'\MOTION_output.csv'),'WriteMode','Append');
writematrix([mvt_score(i_init2:len2)],strcat(folder_fictive,'\neurologicScore_output.csv'),'WriteMode','Append');
end
end
Everything works fine if the number of subfolders is lower than 4 : the good values appear in the files on which is carried out the writematrix function. And the timer callback function are are called one after the other, so both timer work simultaneously.
However if there are 5 subfolders or more, it is not the good values and using the debugging I noticed that the first callback function is triggered the number of 'TasksToExecute', and then only the second callback function seems to be called. That is to say the 2 timers don't work simultaneously.
I have tried to increase p_maj_input and p_maj_output_motion to see if the problem is that matlab can't finish to run before another timer callback function is called but still for 5 subfolders I get the same problem.
Does anyone know where my problem is coming from?
This behavior occurs because one timer hasn't finished executing by the time it triggers again, so the second timer never has a chance to execute until the first timer is finished. If you change the ExecutionMode from 'fixedRate' to 'fixedSpacing', then you'll guarantee that there's time for the second timer to execute.
function duelingTimers()
disp('With ExecutionMode = fixedRate')
t1 = timer('ExecutionMode','fixedRate','Period',0.1,'TasksToExecute',5,'TimerFcn',#timerFcn1);
t2 = timer('ExecutionMode','fixedRate','Period',0.1,'TasksToExecute',5,'TimerFcn',#timerFcn2);
cleanup = onCleanup(#()delete([t1,t2]));
function timerFcn1(~,~)
pause(0.2)
disp('Timer 1');
end
function timerFcn2(~,~)
pause(0.2)
disp('Timer 2');
end
start(t1),start(t2)
wait(t1)
wait(t2)
disp(newline)
disp('With ExecutionMode = fixedSpacing')
t1.ExecutionMode = 'fixedSpacing';
t2.ExecutionMode = 'fixedSpacing';
start(t1),start(t2)
wait(t1)
wait(t2)
end
I'm working on a timer that needs to do some calculations and run some functions at a certain interval. I'm trying to keep the interval as big as possible, but I need it to be kind of fine grained.
Here is the periodic timer with some of the stuff that needs to happen.
So as you can see, every second (the milliseconds passed % 1000 == 0) it will do some stuff if some conditions are met. But also every 10 milliseconds I need to check some stuff.
It seems this is a bit too much, and after running the timer for 2 minutes it already drags 1 second behind. I guess I'm approaching this the wrong way. Could/should I somehow put all that logic in a function that just runs async so the timer can just keep going.
It's not the end of the world if the timer display drags for a few milliseconds every now and then, if it catches up later. But now the whole timer just drags.
_timer = Timer.periodic(Duration(milliseconds: 10), (timer) {
passedMilliseconds = passedMilliseconds + 10;
// METRONOME BEEP AND BLINK
if (passedMilliseconds % currentTimerSettingsObject.milliSecondDivider == 0) {
_playMetronomeBeep();
_startMetronomeBlink();
}
// ONE SECOND
if (passedMilliseconds % 1000 == 0) {
secondsDuration--;
// COUNTDOWN
if (secondsDuration < currentTimerSettingsObject.countDown + 1) {
_player.play('sounds/beep.mp3');
}
// SET COUNTDOWN START VALUES
if (secondsDuration == currentTimerSettingsObject.countDown) {
isCountdown = true;
}
notifyListeners();
}
// TIME IS UP
if (secondsDuration < 0) {
switchToNextTimer();
notifyListeners();
}
});
}
You cannot rely on a timer to deliver events exactly on time. You need to use a more exact method than simply incrementing a counter by 10 on every tick. One example would be to start a Stopwatch before the timer and then (knowing that your ticks will only be on approximately 10ms intervals) read stopwatch.elapsedMilliseconds and base your decisions on that.
You will need to change your logic a bit. For example, you want to know when you pass a 1 second boundary. Previously, with your exact increments of 10 you knew you would eventually reach a round 1000. Now, you might see 995 followed by 1006, and need to deduce that you've crossed a second boundary to run your per second logic.
I am still new to cocos2d and was wondering if any of you guys can help me make a score timer. I seen some questions like this but looks like it is for a way older version of cocos2d. I want the timer to start at zero and go up in mins and seconds. Really appreciate any help or advice I get.
Start a NSTimer that runs every second and calls a method that updates the timer.
Define an integer called seconds and another called minutes in the header.
-(void)updateTheTime {
seconds++;
if (seconds == 60) {
seconds = 0;
minutes++;
}
label.text = [NSString stringWithFormat:#"%i:%i", minutes, seconds];
}
I'm writing for the iPhone and I'm trying to measure the time between maximum accelerations. Imagine you've attached your iPhone to an oscillating spring. What I want to do is measure the frequency of the oscillation. The way I am going about doing this is storing a certain number acceleration values (updated 20 times per second) in an NSMutableArray and comparing the current acceleration value with previous acceleration values.
How do I add each updated acceleration value to the NSMutableArray and at the same time delete values from the back of the array as I don't need them any more?
Thanks in advance!
Are NSMutableArrays -addObject:/-insertObject:atIndex: and -removeLastObject/-removeObjectAtIndex: what you're looking for? See this one for more information.
Think of the array as a wheel. Once you have filled it up, use a rotating index for the replace location.
myIndex = ( ( myIndex + 1 ) % myCount );
[myArray replaceObjectAtIndex:myIndex withObject:newValue];
You can initialize it with a bunch of [NSNull null] objects that you will replace, so you do not need other special processing the first time through.
Once you have finished collecting data, organize the array to have the appropriate element first if it simplifies other operations.
NSRange range = NSMakeRange( 0 , myIndex );
NSArray *temp = [myArray subarrayWithRange:range];
[myArray removeObjectsInRange:range];
[myArray addObjectsFromArray:temp];
Hey guys. I have a method that gets called each second which I want to use to display the time that my app has been doing it's work. Currently the class I'm using (Which I did not create) has a property named progress which stores the total number of seconds.
I have already written some code which takes these seconds and formats it into a readable string. I'm new to this, so pardon me if it's not the best code. I welcome any suggestions:
// hours, minutes, and seconds are instance variables defined as integers
int totalSeconds = (int)streamer.progress;
hours = totalSeconds / (60 * 60);
if (hours > 0)
formattedTimeString = [NSString stringWithFormat:#"%d:", hours]; // WRONG
minutes = (totalSeconds / 60) % 60;
seconds = totalSeconds % 60;
[formattedTimeString stringByAppendingFormat:#"%d:%d", minutes, seconds]; // WRONG
Basically I want it to appear as "3:35" for example to show 3 minutes, 35 seconds. I only want to show the hour section if it has been an hour, in which case it would be "2:3:35" for example (Can anyone recommend a better way to format this?).
The problem I am having is where I actually create/set the string (The lines tagged WRONG). Since this is being done every second, I would easily get a leak if I keep asking for a new string object. I figure I can solve this by releasing the foramttedTimeString at the end of the method, but is this the correct way to accomplish this? Would an NSMutableString help in any way? Is there a better, Cocoa way of doing this? I already asked in #iphonedev # freenode and they said I would have to write this method myself, but I figured I'd ask again.
To provide context: this is an internet radio streaming app (I know there are many already, but I'm just practicing). I want to be able to show the amount of time the stream has been playing for.
Sorry if this question is stupid, heh, like I said I'm new to this.
I would do it something like:
int totalSeconds = (int)streamer.progress;
hours = totalSeconds / (60 * 60);
minutes = (totalSeconds / 60) % 60;
seconds = totalSeconds % 60;
if ( hours > 0 ) {
formattedTimeString = [NSString stringWithFormat:#"%d:%02d:%02d", hours, minutes, seconds];
} else {
formattedTimeString = [NSString stringWithFormat:#"%d:%02d", minutes, seconds];
}
Now at the end, formattedTimeString is the desired time, but you do not "own" it - you must retain it, or store it in a "copy" property if you wish to keep it around.
Note that the %02d gives you a guarenteed two digits, zero filled number, which is usually what you want for numbers in parts of times.
To see how you would do it with stringByAppendingFormat, it would look something like this:
NSString* formattedTimeString = #"";
if ( hours > 0 ) {
formattedTimeString = [formattedTimeString stringByAppendingFormat:#"%d:", hours];
}
formattedTimeString = [formattedTimeString stringByAppendingFormat:#"%d:%02d", minutes, seconds];
However in this case, you'll get times like 3:4:05, rether than a more desirable 3:04:05.
Note that formattedTimeString is being overwritten each time, but that is OK bvecause you do not "own" it at any time, so you are not responsible for releasing it.
Finally, to see it with a mutable string, it might look like this:
NSMutableString* formattedTimeString = [NSMutableString string];
if ( hours > 0 ) {
[formattedTimeString appendFormat:#"%d:", hours];
}
[formattedTimeString appendFormat:#"%d:%02d", minutes, seconds];
Again, the time result is the undesirable 3:4:05, and again you do not own formattedTimeString at the end, so it must be retained or stored with a copy property to keep it around.
For knowing the deltas as time units, you can also do something like this:
// as part of init...
self.gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
// in the timer or wherever you are tracking time deltas...
static NSUInteger unitFlags =
NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *components = [gregorian components:unitFlags
fromDate:myBaseTime
toDate:[NSDate date] options:0];
Then you can reference the parts with something like this [components minute].
Remember, you'll have to release the calendar in dealloc.
Your code looks pretty good. You're not leaking any memory because the string objects you create have a retain count of zero and will be cleaned up by the system. However, if formattedTimeString is not a local variable in your function, you need to retain it at the end to prevent this from happening! To do that, you would add [formattedTimeString retain] to the end of your code block, and then before replacing the string object you would add [formattedTimeString release].
As a general rule, functions with names containing "alloc", "copy", "create", and "new" return objects that have already been retained, (meaning their retain count is +1). It's your responsibility to call release or autorelease on these objects when you're done using them - or they will just start piling up in memory.
Functions like "stringWithFormat:", "imageNamed:", and "arrayWithCapacity:" all return objects with a retain count of zero - so you can safely discard them (as you are in the code sample). If you want to keep them around, you should call retain to make sure they are not cleaned up while you're using them.
All that said, I think the main problem is your use of stringByAppendingFormat:. Since the NSString you're using isn't mutable, that call returns a new string. You'd want to say:
formattedTimeString = [formattedTimeString stringByAppendingFormat:#"%d:%d", minutes, seconds];
Alternatively, you could use an NSMutableString. Since this is something you'll be doing over and over again, I'd recommend doing that. Technically, either way is fine though.
Hope that helps! The whole retain/release thing can get confusing. Just remember that each object has a "retainCount" and once it hits zero there's no telling what happens to the object or it's data.
Hey thanks guys I appreciate the responses.
I ended up doing this, and it works, but I would like to know if you guys see any problems with it:
int totalSeconds = (int)streamer.progress;
[formattedTimeString setString:#""];
hours = totalSeconds / (60 * 60);
if (hours > 0)
[formattedTimeString appendFormat:#"%d:", hours];
minutes = (totalSeconds / 60) % 60;
seconds = totalSeconds % 60;
[formattedTimeString appendFormat:#"%02d:%02d", minutes, seconds];
And then of course in viewDidLoad I instantiate the instance variable formattedTimeString:
formattedTimeString = [[NSMutableString alloc] initWithCapacity:8];
I did not do any retaining/releasing in the first code snippet because I didn't think it was necessary, but I could be wrong. I am, however, releasing in the dealloc method, so I should be fine there.