Swift Nstimer Dynamically Changing Interval

Changing the interval of a timer in an if statement

You could do what you want as follows:

First declare 2 properties (in your class but outside all the function definitions)

var timeOfLastSpawn: CFTimeInterval = 0.0
var timePerSpawn: CFTimeInterval = 1.0

Then, in Update, check to see if the timePerSpawn has been exceeded. If so, call your spawn process which spawns new objects and then reset the time since the last spawn:

override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if (currentTime - timeOfLastSpawn > timePerSpawn) {
spawnObject()
self.timeOfLastSpawn = currentTime
}
}

func spawnObject() {
// Your spawn code here
}

The advantage of making the spawn process a separate function is that you can call it from didMoveToView or any other place to spawn objects outside of the normal time-controlled cycle.

You can change the value of timePerSpawn as necessary to control the rate at which objects are spawned.

You could also look into creating an SKAction that runs spawnObject at specified time intervals, but I think to change the rate at which objects are spawned, you'll have to delete and re-create the SKAction, but your could do this in a setter for timePerSpawn.

You shouldn't really use NSTimer is SpriteKit, as the SpriteKit engine will be unaware of what the timer is doing and can't control it (one example is that the timer keeps running if the set the scene to paused).

How do I change timing for NSTimer?

Sure you can do this. Change repeats:YES to repeats:NO so that the timer doesn't repeat, and then in onTimer, just start a new timer with a longer interval. You need a variable to hold your interval so that you can make it a bit longer each time through onTimer. Also, you probably don't need to retain the timer anymore, as it will only fire once, and when it does, you'll get a new timer.

I'm no Objective-C expert (or iOS expert...) and it's been a while but I think something like this:

float gap = 0.50;

[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:@selector(onTimer) userInfo:nil repeats:NO];

-(void) onTimer {
gap = gap + .05;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:@selector(onTimer) userInfo:nil repeats:NO];
}

Something like that? Oh, and I'm really not too sure about the retain semantics here... read the docs to make sure you don't leak!

How does one change/update the time interval in an NSTimer?

You can't. Invalidate the timer, and create a new one with a different time interval.

You can change the fire time. So if you want to change the time interval after the first firing only, create the timer with that time interval, then change the firing time so that the timer is fired the first time at the time you want.

Change NSTimer interval after a certain number of fires

Make the timer object a member variable. Initially set animation time as 1 second. In the callback invalidate the timer and create a new one with 1 or 4 seconds depending on the counter.

@interface ViewController ()
@property (strong,nonatomic) NSMutableArray *images;
@property (strong,nonatomic) UIImageView *animationImageView;
{
NSTimer *_timer;
}
@end

@implementation ViewController {
NSInteger counter;
}

- (void)viewDidLoad {
[super viewDidLoad];

NSArray *imageNames = @[@"hello.png",@"bye.png",@"helloagain.png",@"bye again"];

self.images = [[NSMutableArray alloc] init];
for (int i = 0; i < imageNames.count; i++) {
[self.images addObject:[UIImage imageNamed:[imageNames objectAtIndex:i]]];
}

self.animationImageView = [[UIImageView alloc] initWithFrame:CGRectMake(60, 95, 86, 90)];
self.animationImageView.image = self.images[0];
[self.view addSubview:self.animationImageView];
self.animationImageView.userInteractionEnabled = TRUE;

UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(bannerTapped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
[self.animationImageView addGestureRecognizer:singleTap];
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(changeImage:) userInfo:nil repeats:YES];
}

-(void)changeImage:(NSTimer *) timer {
[_timer invalidate];
if (counter == self.images.count - 1 ) {
counter = 0;
}else {
counter ++;
}
if(counter == 0 || counter == 1)
{
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(changeImage:) userInfo:nil repeats:YES];
}
else if(counter == 2 || counter == 3)
{
_timer = [NSTimer scheduledTimerWithTimeInterval:4 target:self selector:@selector(changeImage:) userInfo:nil repeats:YES];
}
self.animationImageView.image = self.images[counter];
}

Set a timer with variable intervals in swift

Here is a basic idea on how to approach the problem

struct RequestMananger {
var timers: [Timer] = []

mutating func startSequence() {
var delay = 10.0
sendRequest()

timers.append(scheduleTimer(delay))
delay += 20
timers.append(scheduleTimer(delay))
delay += 40
timers.append(scheduleTimer(delay))
delay += 60
timers.append(scheduleTimer(delay, repeats: true))
}

private func scheduleTimer(_ delay: TimeInterval, repeats: Bool = false) -> Timer {
return Timer.scheduledTimer(withTimeInterval: delay, repeats: false, block: { timer in
self.sendRequest()
})
}

func sendRequest() {

}

func cancelTimers() {
timers.forEach { $0.invalidate() }
}
}

How can I use Timer (formerly NSTimer) in Swift?

This will work:

override func viewDidLoad() {
super.viewDidLoad()
// Swift block syntax (iOS 10+)
let timer = Timer(timeInterval: 0.4, repeats: true) { _ in print("Done!") }
// Swift >=3 selector syntax
let timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
// Swift 2.2 selector syntax
let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MyClass.update), userInfo: nil, repeats: true)
// Swift <2.2 selector syntax
let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)
}

// must be internal or public.
@objc func update() {
// Something cool
}

For Swift 4, the method of which you want to get the selector must be exposed to Objective-C, thus @objc attribute must be added to the method declaration.

iOS: How to call a function sequentially after different (defined) amount of time?

There are multiple things wrong here:

  1. Selector(executeCustomScheduler(nextTimeIndex)) creates a selector based on the return value of executing executeCustomScheduler(nextTimeIndex) one time
  2. withObject: self - why would you pass self?
  3. why are you using performSelector at all?
  4. executionTimes is not in milliseconds but in seconds, or at least the method expects them to be
  5. final problem: your argument is a primitive Int which gets really troublesome when passing it around in the performSelector

Solutions:

  1. Selector("executeCustomScheduler:") is the correct selector
  2. nextTimeIndex is the correct argument to pass along
  3. it would probably be better to use something that has a bit more type security, anything with selectors is wide open to a ton of problems regarding renaming e.g.
  4. divide the values by 1000 before passing them into the performSelector
  5. I do not really have a good solution: the easiest and probably worst one: use a String instead of an Int :/

Better solution:
Use dispatch_after, get rid of those pesky selectors and be typesafe all the way through:

class Obj {

let executionTimes = [0, 1500, 3500, 4700]

func executeCustomScheduler(timeIndex: Int) {
NSLog("Hello")

let time = executionTimes[timeIndex]
let nextTimeIndex = (timeIndex + 1) % executionTimes.count

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(Double(time) / 1000 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
self.executeCustomScheduler(nextTimeIndex)
}
}
}

let obj = Obj()
obj.executeCustomScheduler(0)

Metronome SwiftUI, Change timer interval whenever the @State var is changed

The easiest way to perform code when a @State value changes is to add an onChange modifier to a child view of the view where you defined your @State, e.g.:

struct ContentView: View {
@State private var period: Double = 0.5

var body: some View {
Slider(value: period, in: 0.25...5, step: 0.25)
.onChange(of: period) { newValue in
// perform your code here
}
}
}

See also Apple's documentation and an example on Hacking With Swift.



Related Topics



Leave a reply



Submit